在nhibernate queryover查询中指定获取策略(select,join等)

时间:2011-03-10 16:21:29

标签: c# nhibernate fetch queryover

我正在尝试使用 QueryOver 创建查询,该查询将使用选择 SubSelect 模式获取集合。有问题的实体是Track。我想加载一个名为TrackPrices的集合,我在查询中执行此操作:

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

但是,这会创建一个左连接,这会导致分页问题。我希望它执行单独的选择子选择。有什么想法可以吗?据我所知,使用标准API可以做到:

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

但我想在代码中避免使用魔术字符串,因此我更倾向于使用QueryOver API。

3 个答案:

答案 0 :(得分: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();可以用您自己的方法替换,以从会话工厂中检索当前会话。

希望它有所帮助!

答案 1 :(得分:1)

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

答案 2 :(得分:1)

组合分页和急切提取很棘手。

如果指定fetch以通过Criteria API进行选择,则TrackPrices中的每个项目都将加载到单独的查询 - N + 1问题中。你根本不需要急于加载。

您可以在映射中设置TrackPrices的批量大小以缓解N + 1问题。 有关于在此article中混合热切提取和分页的一些详细信息。