1

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

4

2 回答 2

1

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

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

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

我会:

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

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

于 2013-08-05T13:15:38.530 回答
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
}
于 2013-08-06T11:42:48.737 回答