NHibernate& LINQ:使用Fetch()和自定义ToPagedList方法

时间:2011-06-13 23:51:48

标签: linq nhibernate pagination linq-to-nhibernate

我在使用nHibernate Fetch()(或FetchMany())方法时遇到问题,我的分页方法使用Futures来获取所需的信息。而且我不确定如何解决它,但我确切知道它在做什么。让我解释一下到目前为止的情况。

我正在使用找到here的扩展方法让我将行计数作为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);
        }

它工作得很好,使用它然后我可以结合获取行计数并将我的结果集转换为仅生成单个数据库命中的signle分页方法。我的Paging方法看起来像这样。

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(),你不能这样做,因为错误是正确的。获取的关联的所有者不在选择列表中(至少它不在其中一个中),我的select实际上是第一个查询是针对单个整数。我想也许我可以在ToPagedList中删除一次用于任何提取的Expression节点,但我不知道它是否可能或者它有多丑。我正在寻找一些替代方案,可以让我们获得我想要的行为,同时绕过Fetching如何工作的限制。有什么想法吗?

1 个答案:

答案 0 :(得分:1)

您可以按如下方式修改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));

我知道它稍微不那么优雅,但它会起作用,而且比修改现有表达式更容易。