NHibernate - Eager加载具有多个查询的对象的图形

时间:2013-08-02 15:23:03

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

我想缓存一个永远不会改变的聚合,只能通过根对象访问(所有其他实体只能通过使用根对象上的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超出范围之后我也可以访问所有内容?

2 个答案:

答案 0 :(得分:1)

我认为其中有几个问题。

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

我会通过使用批量大小避免过多的查询,这是最干净,最简单的解决方案,在大多数情况下都足够好了#34;它对业务逻辑完全透明,这使它非常酷。

我会:

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

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

答案 1 :(得分: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
}