【问题标题】:NHibernate iStatelessSession returns duplicate parent instances on eager fetchNHibernate iStatelessSession 在急切获取时返回重复的父实例
【发布时间】:2015-02-27 15:18:25
【问题描述】:

我正在尝试获取一个根实体并急切地获取它的子实体。但是因为我使用的是 NHibernate 的 IStatelessSession,所以它会为每个孩子返回根实体的副本。使用ISession,可以解决

.TransformUsing(new DistinctRootEntityResultTransformer()) 

但对于 IStatelessSession 却不是。

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

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

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

【问题讨论】:

  • 如果你让你的孩子保持 ISet 而不是 IList,这个问题就不会出现

标签: nhibernate fluent-nhibernate fetch eager istatelesssession


【解决方案1】:

我会说:不要不要使用 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

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

  • 标准会话,不使用(让它立即处理)
  • 加载根实体(父)列表并
  • 让 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

如上述代码 sn-p 所示,为避免 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

【讨论】:

    猜你喜欢
    • 2011-06-24
    • 1970-01-01
    • 1970-01-01
    • 2012-11-09
    • 2017-09-28
    • 2016-10-07
    • 2017-10-19
    • 1970-01-01
    • 2011-04-02
    相关资源
    最近更新 更多