NHibernate 和 NHibernate LINQ:将 Fetch() 与自定义 ToPagedList 方法结合使用

发布于 2024-11-15 07:04:08 字数 2075 浏览 13 评论 0原文

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

我正在使用此处 让我获得行计数作为未来值。它看起来像这样。

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

I have a problem with using the nHibernate Fetch() (or FetchMany()) method with my paging method which uses Futures to get the information it needs. And I'm not sure how to fix it but I know exactly what it's doing. Let me explain what I have so far.

I'm using an extension method found here to let me get a row count as a Future value. it looks like this.

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);
        }

It works great, using this I can then combine getting a row count and getting my result set into a signle paging method that only generates a single database hit. My Paging method looks like this.

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();
        }

With this in place I can make queries like the following.

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

This much works like a charm. However now I need to be able to define certain relationships as eager loaded, in this case it might look like this.

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

This blows up with a QueryException with the description "Query specified join fetching, but the owner of the fetched association was not present in the select list". The reason for this is because of my paging method, it's trying to apply an aggregate row count on the query which has the Fetch() on it, and you can't do that, because the error is right. The owner of the fetched association wasn't in the select list (at least it isn't in one of them), my select is essentially for the first query is for a single integer. I thought maybe I could rip out the Expression nodes once in the ToPagedList that are for any fetching but I have no idea if it's possible or how ugly it would be. I'm looking for some alternatives that might let be get the behavior I want while bypassing the limitation on how Fetching works. Any thoughts?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

许久 2024-11-22 07:04:08

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

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

You could modify ToPagedList as follows:

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();
}

And use it like this:

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

I know it's slightly less elegant, but it will work, and it's way easier than modifying an existing expression.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文