NHibernate & LINQ: использование Fetch () с пользовательским методом ToPagedList - PullRequest
3 голосов
/ 14 июня 2011

У меня проблема с использованием метода nHibernate Fetch () (или FetchMany ()) с моим методом подкачки, который использует Futures для получения необходимой информации. И я не уверен, как это исправить, но я точно знаю, что он делает. Позвольте мне объяснить, что у меня есть.

Я использую метод расширения, найденный здесь , чтобы позволить мне получить количество строк в качестве значения Future. это выглядит так.

public static IFutureValue<TResult> ToFutureValue<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<IQueryable<TSource>, TResult>> selector) where TResult : struct
        {
            var provider = (NhQueryProvider)source.Provider;
            var method = ((MethodCallExpression)selector.Body).Method;
            var expression = Expression.Call(null, method, source.Expression);
            return (IFutureValue<TResult>)provider.ExecuteFuture(expression);
        }

Это прекрасно работает, с помощью этого я могу затем объединить получение количества строк и получение моего результата в метод подкачки сигналов, который генерирует только одно попадание в базу данных. Мой метод пейджинга выглядит следующим образом.

public static IList<T> ToPagedList<T>(this IQueryable<T> query, int pageIndex, int pageSize, out int count)
        {
            var futureCount = query.ToFutureValue(x => x.Count());
            var futureResults = pageIndex == 0 && pageSize == 0 ? query.ToFuture() : query.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToFuture();
            count = futureCount.Value;
            return futureResults.ToList();
        }

Имея это, я могу делать запросы, подобные следующим.

repositoryInstance.Query().Where(x=>x.SomeTextField.Contains("lake")).ToPagedList(pageIndex, pageSize, out count);

Это много работает как шарм. Однако теперь мне нужно иметь возможность определять определенные отношения как загруженные, в этом случае это может выглядеть следующим образом.

repositoryInstance.Query().Where(x=>x.SomeTextField.Contains("lake")).FetchMany(x=>x.Details).ToPagedList(pageIndex, pageSize, out count);

Это приводит к возникновению исключения QueryException с описанием "Запрос указывает объединение выборки, но владелец извлеченной ассоциации не присутствует в списке выбора". Причина в том, что из-за моего метода подкачки он пытается применить совокупный счетчик строк к запросу, на котором есть Fetch (), и вы не можете этого сделать, потому что ошибка верна. Владелец выбранной ассоциации не был в списке выбора (по крайней мере, его нет в одном из них), мой выбор, по сути, для первого запроса - для одного целого числа. Я подумал, что, может быть, мне удастся разорвать узлы Expression в ToPagedList, которые предназначены для любой выборки, но я понятия не имею, возможно ли это или насколько уродливо это будет. Я ищу некоторые альтернативы, которые позволят получить желаемое поведение, обходя ограничение на то, как работает выборка. Есть мысли?

1 Ответ

1 голос
/ 14 июня 2011

Вы можете изменить ToPagedList следующим образом:

public static IList<T> ToPagedList<T>(this IQueryable<T> query, int pageIndex,
                       int pageSize, out int count,
                       Func<IQueryable<T>, IQueryable<T>> filterResult)
{
    var futureCount = query.ToFutureValue(x => x.Count());
    //change only the results query, not the count one
    if (customAction != null)
        query = filterResult(query);
    var futureResults = pageIndex == 0 && pageSize == 0
                            ? query.ToFuture()
                            : query.Skip((pageIndex - 1) * pageSize)
                                   .Take(pageSize).ToFuture();
    count = futureCount.Value;
    return futureResults.ToList();
}

И используйте это так:

repositoryInstance.Query().Where(x => x.SomeTextField.Contains("lake"))
                  .ToPagedList(pageIndex, pageSize, out count,
                               q => q.FetchMany(x => x.Details));

Я знаю, что это немного менее элегантно, но это будет работать, и это намного проще, чем модифицировать существующее выражение.

...