【问题标题】:NHibernate 4 upgrade - Cannot simultaneously fetch multiple bagsNHibernate 4 升级 - 无法同时提取多个包
【发布时间】:2015-01-26 06:19:45
【问题描述】:

我尝试将 NH 3.3.1.4000 升级到最新版本 NH 4.0.2.4000,但 FetchMany 和 ThenFetchMany 出现问题。

在这篇文章中,我了解到这个旧功能不再有效,Breaking changes with NHibernate 4 upgrade

在新的 NH 版本上进行这种获取的正确方法是什么?

代码示例:

var IdsList = new List { /* Some Ids */ };
session.Query<A>()
.FetchMany(x=>x.B_ObjectsList)
.ThanFetchMany(x=>x.C_ObjectsList)
.Where(x=>IdsList.Contains(x=>x.Id))
.ToList();

类:

Public Class A
{
    public int Id {get;set;}
    public IList<B> B_ObjectsList{get;set;}
}

Public Class B
{
    public int Id {get;set;}
    public IList<C> C_ObjectsList {get;set;}
}

Public Class C
{
    public int Id {get;set;}
}

映射:

<class name="A" table="A">
<id name="Id" type="int" column="Id" unsaved-value="0">
  <generator class="identity" />
</id>
<bag name="B" table="B" inverse="false" lazy="true"
cascade="all-delete-orphan">
</class>

<class name="B" table="B">
<id name="Id" type="int" column="Id" unsaved-value="0">
  <generator class="identity" />
</id>
<bag name="C" table="C" inverse="false" lazy="true"
cascade="all-delete-orphan">
</class>


<class name="C" table="C">
<id name="Id" type="int" column="Id" unsaved-value="0">
  <generator class="identity" />
</id>
</class>

【问题讨论】:

    标签: c# .net nhibernate nhibernate-4


    【解决方案1】:

    大概

    var IdsList = new List { /* Some Ids */ };
    var results = session.Query<A>()
        .FetchMany(x => x.B_ObjectsList)
        .Where(x=>IdsList.Contains(x.Id))
        .ToList();
    
    // initialize C_ObjectsList
    var bIds = results.SelectMany(x => x.B_ObjectsList).Select(b => b.Id).Distinct().ToList();
    session.Query<B>()
        .FetchMany(x => x.C_ObjectsList)
        .Where(b => bIds.Contains(b.Id))
        .ToList();
    
    return results;
    

    【讨论】:

    • 谢谢,我检查过了,它可以工作。但是如果我进一步使用它不起作用,我可以在不为每个连接查询数据库的情况下进行这种获取吗?
    • 使用 sql 只有两种可能性:大笛卡尔积或每个关联级别的查询。第一个通常很容易导致较大的结果,因此这可能是它被删除的原因。如果关联都在同一级别,则可以使用 Futures 减少到数据库的往返次数
    • 太糟糕了,如果此更改导致数据库有更多方法,它会被阻止,我猜想访问与 where 过滤器映射的关系也会更加困难。谢谢,非常感谢。
    【解决方案2】:

    如果 B 引用了 A,你可以这样做:

    var IdsList = new List { /* Some Ids */ };
    var results = session.Query<A>()
                         .Fetch(a => a.B_ObjectsList)
                         .Where(a => IdsList.Contains(a.Id))
                         .ToList();
    
    // initialize C_ObjectsList
    var aQuery = session.Query<A>()
                        .Where(x => IdsList.Contains(x.Id));
    
    session.Query<B>()
           .Fetch(b => b.C_ObjectsList)
           .Where(b => aQuery.Contains(b.A)
           .Prefetch();
    

    这样做的好处是不受数据库最大参数的限制,在 SQL Server 中默认为 2100。 而不是ToList(),我使用这个扩展方法:

    static public void Prefetch<T>(this IQueryable<T> query)
    {
        // ReSharper disable once ReturnValueOfPureMethodIsNotUsed
        query.AsEnumerable().FirstOrDefault();
    }
    

    【讨论】:

      猜你喜欢
      • 2017-08-20
      • 2019-03-18
      • 2016-11-09
      • 1970-01-01
      • 2014-10-16
      • 2017-07-26
      • 1970-01-01
      • 2020-09-30
      • 2016-07-29
      相关资源
      最近更新 更多