C# NHibernate-具有多个查询的对象的渴望加载图

C# NHibernate-具有多个查询的对象的渴望加载图,c#,nhibernate,caching,second-level-cache,C#,Nhibernate,Caching,Second Level Cache,我想缓存一个只可由根对象访问的永不更改的聚合(所有其他实体只能通过使用根对象上的Reference/hasmall属性访问) 我应该使用NHibernate(我们已经在使用)二级缓存,还是构建某种提供对聚合中所有实体的访问的单例更好 我发现了一篇关于使用MultiQuery获取所有信息的博文,但我的数据库不支持它 做这件事的“老办法”是 从所有聚合表中选择* 循环实体并手动设置引用和集合 比如: foreach (var e in Entities) { e.Parent = loa

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

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

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

做这件事的“老办法”是

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

foreach (var e in Entities)
{
    e.Parent = loadedParentEntities.SingleOrDefault(pe => e.ParentId = pe.Id);
}
但肯定有办法告诉NHibernate帮我做这件事

更新

目前,我只尝试从数据库中获取所有内容,希望NHibernate完成所有引用设置。但是,它没有:(

var getRoot=Session.Query().ToList();
var getRoot_hasMany=Session.Query().ToList();
var getRoot_hasMany_ref=Session.Query().ToList();
var getRoot_hasMany_hasMany=Session.Query().ToList();
域:

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

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

但是,当访问诸如
getRoot.First().HasMany.First().Ref
getRoot.First().HasMany.First().HasMany().First()
之类的属性时,即使
ISession
已经知道了一切,仍然会执行额外的查询


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

我认为其中有几个问题

我不再试图欺骗NHibernate太多。我不会从多个线程访问实体,因为它们通常不是线程安全的。至少在使用延迟加载时是这样。因此缓存延迟实体是件坏事

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

我想:

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

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

如果整个对象树从未更改(配置设置?),则只需在初始化所有引用/集合的情况下高效加载它们即可

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
}
使用(var Session=Sessionfactory=OpenSession())
{
var root=Session.Query().FetchMany(x=>x.Collection).ToFutureValue();
Session.Query().Fetch(x=>x.Ref).FetchMany(x=>x.Collection.ToFuture();
//用root.Value做一些事情
}

不是我所期望的,但听起来像是很好的建议,谢谢。
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
}