【问题标题】:NHibernate - Eager load graphs of objects with multiple queriesNHibernate - 具有多个查询的对象的渴望加载图
【发布时间】:2013-08-03 22:38:08
【问题描述】:

我想缓存一个只能由根对象访问的永不更改的聚合(所有其他实体只能通过使用根对象上的 Reference/HasMany 属性来访问)?

我应该使用 NHibernate(我们已经在使用)二级缓存还是构建某种单例来提供对聚合中所有实体的访问更好?

我发现了一篇关于使用 MultiQuery 获取所有内容的博文,但我的数据库不支持它。

这样做的“旧方法”是

  • 从所有聚合表中选择 *
  • 循环实体并手动设置引用和集合

类似:

foreach (var e in Entities)
{
    e.Parent = loadedParentEntities.SingleOrDefault(pe => e.ParentId = pe.Id);
}

但肯定有办法告诉 NHibernate 为我做这件事吗?

更新

目前我尝试仅从数据库中获取所有内容,并希望 NHibernate 完成所有参考设置。然而它没有:(

var getRoot = Session.Query<RootObject>().ToList();
var getRoot_hasMany = Session.Query<RootObjectCollection>().ToList();
var getRoot_hasMany_ref = Session.Query<RootObjectCollectionReference>().ToList();
var getRoot_hasMany_hasMany = Session.Query<RootObjectCollectionCollection>().ToList();

域:

根对象是getRoot。这些有一个集合属性“HasMany”。这些 HasMany 每个都有一个返回 GetRoot 的引用,一个对另一个实体的引用 (getRoot_hasMany_ref),以及它们自己的集合 (getRoot_hasMany_hasMany)。如果这没有意义,我将创建一个 ERD,但实际结构与问题并不真正相关(我认为)。

这会导致执行 4 个查询。 (这很好)

但是,当访问像 getRoot.First().HasMany.First().RefgetRoot.First().HasMany.First().HasMany().First() 这样的属性时,即使 ISession 应该已经知道所有内容,它仍然会导致执行额外的查询?

那么,我如何告诉 NHibernate 执行这 4 个查询,然后在不使用任何代理属性的情况下构建图形,……这样即使在 ISession 超出范围后我也可以访问所有内容?

【问题讨论】:

    标签: c# nhibernate caching second-level-cache


    【解决方案1】:

    如果整个对象树永远不会改变(配置设置?)那么只需在所有引用/集合初始化的情况下有效地加载它们

    using(var Session = Sessionfactory = OpenSession())
    {
        var root = Session.Query<RootObject>().FetchMany(x => x.Collection).ToFutureValue();
        Session.Query<RootObjectCollection>().Fetch(x => x.Ref).FetchMany(x => x.Collection).ToFuture();
    
        // Do something with root.Value
    }
    

    【讨论】:

      【解决方案2】:

      我认为有几个问题合二为一。

      我不再试图过多地欺骗 NHibernate。我不会从多个线程访问实体,因为它们通常不是线程安全的。至少在使用延迟加载时。因此缓存惰性实体是邪恶的。

      我会通过使用批量大小来避免过多的查询,这是迄今为止最简洁和最简单的解决方案,并且在大多数情况下“足够好”。它对业务逻辑完全透明,非常酷。

      我愿意:

      • 考虑根本不缓存实体。使用 NH 一级缓存(例如:始终使用 session.Get() 加载它)。当单个事务中仅使用一小部分数据时,请使用延迟加载。
      • 是否有已证实需要缓存数据,考虑完全关闭延迟加载(通过使实体非延迟并将所有集合设置为非延迟。加载实体一次并缓存它。在加载数据时访问数据时仍要考虑线程安全。
      • 如果实体是惰性的,因为某些相同类型的实例不在缓存中,请考虑使用类似 DTO 的结构作为缓存。复制非实体的类似类结构中的所有数据。这听起来可能需要做很多额外的工作,但最终会避免很多奇怪的问题,并为您节省很多时间。

      通常,查询时间不如刷新时间重要。 NH 使用此时间来查找会话中更改的实体。为避免这种情况,请在可能的情况下将实体设为只读。

      【讨论】:

      • 不完全符合我的预期,但听起来像是可靠的建议,谢谢。
      猜你喜欢
      • 2014-12-15
      • 2011-01-11
      • 2016-01-10
      • 1970-01-01
      • 2013-05-08
      • 1970-01-01
      • 2014-11-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多