Nhibernate:急切加载两个子集合(一个是组件列表)

Mig*_*ues 8 nhibernate

我有一个Parent类,它有两个子集合ChildCollectionA和ChildCollectionB.ChildCollectionA被映射为关联,并具有自己的ID:

HasMany(parent => parent.ChildCollectionA)
.KeyColumn("IDParent")
.AsBag().Cascade.AllDeleteOrphan();
Run Code Online (Sandbox Code Playgroud)

和ChildCollectionB映射有一个组件列表:

HasMany(parent => parent.ChildCollectionB)
    .Table("ChildCollectionBTable")
    .KeyColumn("IDParent")
    .Component(m=>
                {
                    m.References(childB => childB.Task, "IDTask").Not.LazyLoad().Not.Nullable();
                    m.Map(childB  => childB.Date, "Date").Not.Nullable();

                } 
        )
    .AsBag().Cascade.AllDeleteOrphan();
Run Code Online (Sandbox Code Playgroud)

我现在需要DataBase中的所有Parent,因为我必须执行一些需要ChildCollectionA和ChildCollectionB的操作.

所以我不得不急于加载它们,我使用获取模式首先急切加载ChildCollectionA:

    var queryParents = session.CreateCriteria().SetFetchMode("ChildCollectionA",FetchMode.Eager).Add(Expression.Le("ParentDate",endDate));

它返回492个父母(应该是481),我执行的操作的总价值是32,847.46€(应该是30,790.87€).所以我必须消除父副本:

var queryParents = session.CreateCriteria<Parent>()
    .SetFetchMode("ChildCollectionA", FetchMode.Eager)
    .Add(Expression.Le("ParentDate",endDate))
    .SetResultTransformer(new DistinctRootEntityResultTransformer());
Run Code Online (Sandbox Code Playgroud)

我只用ChildCollectionB尝试了同样的热切加载

var queryParents = session.CreateCriteria<Parent>()
    .SetFetchMode("ChildCollectionB", FetchMode.Eager)
    .Add(Expression.Le("ParentDate",endDate))
    .SetResultTransformer(new DistinctRootEntityResultTransformer());
Run Code Online (Sandbox Code Playgroud)

在这两种情况下返回481父母OK,价值为30,790.87€OK.

但是我需要同时加载两个集合,我这样做了:

var queryParents = session.CreateCriteria<Parent>()
    .SetFetchMode("ChildCollectionA", FetchMode.Eager)
    .SetFetchMode("ChildCollectionB", FetchMode.Eager)
    .Add(Expression.Le("ParentDate",endDate))
    .SetResultTransformer(new DistinctRootEntityResultTransformer());
Run Code Online (Sandbox Code Playgroud)

它返回了481个父母,价值为32,602.57欧元(应该是30,790.87欧元).

现在返回的父项数是正确的,但在其他地方有重复项,值取决于集合而不是父项,因此重复项必须位于ChildCollections中的某个位置.

现在我正在使用一个丑陋的解决方案:

var queryParents = session.CreateCriteria<Parent>()
    .SetFetchMode("ChildCollectionA", FetchMode.Eager)
    .Add(Expression.Le("ParentDate",endDate))
    .SetResultTransformer(new DistinctRootEntityResultTransformer());

parents= queryParents.List<Parent>();

  foreach (Parent p in parents)
  {
      NHibernateUtil.Initialize(p.ChildCollectionB);
  }
Run Code Online (Sandbox Code Playgroud)

它回来了481个父母好,价值是30,790.87€OK.

当我急切加载两个集合时,问题就发生了,如果我急切加载一个,然后强制lazyload到另一个,它的工作.我不知道ChildCollectionB作为组件列表而不是关联的映射是否与此有关...

有线索吗?

谢谢

dot*_*joe 4

我认为问题是两个集合之间的笛卡尔积不是由 DistinctRootEntityTransformer 处理的......所以您将在集合中的某个地方有重复的数据。

要急切地加载多个集合,需要进行多个查询。

var queryParents = session.CreateCriteria<Parent>()
    .SetFetchMode("ChildCollectionA", FetchMode.Eager)
    .Add(Expression.Le("ParentDate",endDate))
    .SetResultTransformer(new DistinctRootEntityResultTransformer());

//load CollectionB in second query...it's linked together by NH
session.CreateCriteria<Parent>()
    .SetFetchMode("ChildCollectionB", FetchMode.Eager)
    .Add(Expression.Le("ParentDate",endDate))
    .List();
Run Code Online (Sandbox Code Playgroud)

我通常做的是获取主要实体以及所有必需的多对一关联。然后,我将使用 MultiCriteria 急切地将所需的集合提取到会话中。如果只有两个集合,有时我会像上面那样获取具有不同根实体的第一个集合。

有关详细信息,请参阅具有许多子集合的预加载聚合