12

我正在尝试使用QueryOver创建一个查询,它将使用SelectSubSelect模式获取一个集合。有问题的实体是Track。我想加载一个名为 的集合TrackPrices,我在查询中这样做:

q = q.Fetch(item => item.TrackPrices).Eager;

但是,这会创建一个左连接,从而导致分页问题。我希望它执行单独的selectsubselect。知道是否可以做到吗?据我所知,使用标准 API 可以:

q.DetachedCriteria.SetFetchMode("TrackPrices", FetchMode.Select);

但我想避免在代码中使用魔法字符串,因此我更喜欢使用 QueryOver API 来完成它。

4

3 回答 3

3

从我发布这个问题开始,我已经设法找到其他人可能会觉得有用的解决方法/解决方案。

基本上,在这种情况下,您必须首先创建另一个查询,该查询明确选择主查询的主键以及分页。由于 DISTINCT(ID) 将只返回您想要的结果,因此您可以使用 SQL 的分页没有任何问题。然后,您重新运行主查询,不进行分页,但使用 ID 位于返回列表之一中的条件。我创建了一个通用方法,它采用标准,查找返回的 ID 并将它们作为条件添加到主要标准。下面的代码:

public static void LimitCriteriaByPrimaryKeys(this NHibernate.ICriteria criteria, string primaryKeyName, int pageNum, int pageSize)
    {
        var session = NHManager.Instance.GetCurrentSessionFromContext();
        if (pageSize <= 0) pageSize = Int32.MaxValue - 1;
        var nhSession = NHManager.Instance.GetCurrentSessionFromContext();
        var pagingCriteria = (ICriteria)criteria.Clone();
        IList ids = null;
        var pKeyIDName = Projections.Property(primaryKeyName);  
        var pKeyProjection = Projections.Distinct(pKeyIDName); 
        {
            {
                //paging
                pagingCriteria.SetProjection(pKeyProjection); //sets the primary key distinct projection
                if (pageSize > 0)
                {

                    if (pageNum < 1)
                        pageNum = 1;
                    int skipAmt = (pageNum - 1) * pageSize;
                    pagingCriteria.SetFirstResult(skipAmt);
                    pagingCriteria.SetMaxResults(pageSize); 

                    ids = pagingCriteria.List(); //this returns the distinct list of IDs which should be returned for the given page & size

                }
            }
        }
        {
            if (ids != null && ids.Count > 0)
            {
                criteria.Add(Expression.In(pKeyIDName, ids));   //adds the primary key restriction
                var crit = criteria;
                crit.SetResultTransformer(new NHibernate.Transform.DistinctRootEntityResultTransformer());
            }
            else
            {
                criteria.Add(Expression.Eq(pKeyIDName, 0)); //this is added specifically so that the main criteria returns NO results
                criteria.Add(Expression.Eq(pKeyIDName, 1));
            }
        }
    }

这些方法NHManager.Instance.GetCurrentSessionFromContext();可以替换为您自己的方法,以从会话工厂检索当前会话。

希望能帮助到你!

于 2011-05-16T09:43:19.360 回答
1

我知道这不是您所要求的,但最坏的情况是您可以在此处使用不同的方法以类型安全的方式封装您的魔术字符串: C# String enums

于 2011-04-19T16:49:24.240 回答
1

结合分页和急切获取是很棘手的。

如果您通过 Criteria API 指定 fetch 来选择,那么 TrackPrices 中的每个项目都将在单独的查询中加载 - N+1 个问题。您根本不需要急于加载。

您可以在映射中为 TrackPrices 设置批量大小以减轻 N+1 问题。本文中有一些关于混合 Eager fetching 和 paging 的细节。

于 2011-05-14T17:25:53.127 回答