NHibernate iStatelessSession在eager fetch上返回重复的父实例

时间:2014-12-31 14:55:54

标签: nhibernate fluent-nhibernate fetch eager istatelesssession

我正在尝试获取一个根实体,并渴望获取它的子实体。但是因为我正在使用NHibernate的IStatelessSession,它会返回每个子节点的根实体的重复项。使用ISession,它将通过

解决
.TransformUsing(new DistinctRootEntityResultTransformer()) 

但是对于IStatelessSession,它不是。

基本上它是关于下面的代码,其中只有一个Parent实例,持有3个Childs。

var result = session.QueryOver<Parent>()
.Fetch(i => i.Childs).Eager();

这将返回3个重复的Parent实例,而不只是一个。有人有解决方案吗?

1 个答案:

答案 0 :(得分:2)

我会说:使用StatelessSession。它不适用于此用例。

13.2. The StatelessSession interface

  

或者,NHibernate提供了一个面向命令的API,可用于以分离对象的形式将数据流入和流出数据库。 IStatelessSession没有与之关联的持久化上下文,也没有提供许多更高级别的生命周期语义。 特别是,无状态会话不实现第一级缓存,也不与任何第二级或查询缓存交互。它不实现事务性后写或自动脏检查。使用无状态会话执行的操作不会级联到关联的实例。 无状态会话会忽略集合。通过无状态会话执行的操作绕过NHibernate的事件模型和拦截器......

我刚试过这里解释:NHibernate: Select one to Many Left Join - Take X latest from Parent,这里的问题是,你的JOIN导致了这个SQL结果,不适合分页(迟早需要)

PARENT1 CHILD1
PARENT1 CHILD2
PARENT1 CHILD3
PARENT2 CHILD4
PARENT2 CHILD5 // if we would take 5 records, the parent2 won't get child6
PARENT2 CHILD6

所以这个结果集不是要走的路。我强烈建议:使用

  • 标准会话,不使用(立即处置)
  • 加载根实体(Parent)和
  • 的列表
  • 让NHibernate懒惰加载他们的孩子 - 在单独的SQL查询中。

查询可能/应该是这样的:

ISessionFactory factory = ...;
using (var session = factory.OpenSession())
{
    var list = session.QueryOver<Parent>()
    .Skip(100)
    .Take(25)
    .List<Parent>();

    list.Last() // this will load all occupations at once
        .Childs // if batch-size is higher than page size
        .Any(); // otherwise touch more items

} // session is closed and disposed

如上面的代码片段所示,为了避免1 + N问题,我们必须使用智能映射功能之一:

19.1.5. Using batch fetching

  

NHibernate可以有效地使用批量提取,也就是说,如果访问一个代理(或集合),NHibernate可以加载几个未初始化的代理。批量提取是懒惰选择提取策略的优化。有两种方法可以调整批处理获取:在类和集合级别上。

     

更容易理解批量提取类/实体。想象一下,您在运行时遇到以下情况:您在一个ISession中加载了25个Cat实例,每个Cat都有一个对其所有者的引用,一个Person。 Person类使用代理映射,lazy =“true”。如果您现在遍历所有猫并在每个猫上调用cat.Owner,NHibernate将默认执行25个SELECT语句,以检索代理所有者......

父映射应该是:

HasMany(x => x.Childs)
    ...
    .BatchSize(100) // should be at least 25

请检查以下内容:

注意:有些人可能会建议您使用Result Transforemer,就像您尝试过的那样。这个解决方案可以工作,但是在内存中用C#完成,所以所有数据都被加载(多行)然后缩小。我永远不会用那个。检查:Criteria.DISTINCT_ROOT_ENTITY vs Projections.distinct