为什么期货不缓存在会话一级缓存中?
Why futures are not cached in session 1st level cache?
我有 "static" 个只读实体,我只是用 QueryOver<T>().List<T>()
加载它们。他们所有的属性都不是"lazy"。所以他们中的一些人有N+1问题。
我尝试使用Future
来避免N+1。但看起来 NH 将实体属性视为 "lazy"。当我访问它们时,它甚至会从数据库中一个一个地重新加载实体(导致相同的 N+1 情况),尽管所有实体都是初步预加载的并且应该缓存在会话一级缓存中。这是我的代码:
var futures = new List<IEnumerable>();
futures.Add(s.QueryOver<DailyBonus>().Future<DailyBonus>());
futures.Add(s.QueryOver<DailyBonusChestContent>().Future<DailyBonusChestContent>());
// ... other entities ...
// all queries should be sent with first enumeration
// but I want to ensure everything is loaded
// before using lazy properties
foreach (IEnumerable future in futures)
{
if (future.Cast<object>().Any(x => false)) break;
}
// now everything should be in cache, right?
// so I can travel the whole graph without accessing db?
Serializer.Serialize(ms, futures); // wow, N+1 here!
我使用 hibernatingrhinos 分析器检查了此行为。
那么这是怎么回事?
使用 futures 加载带有集合的实体的唯一正确方法是 Fetch
,这意味着每个查询的连接:
var q = session.Query<User>().Where(x => x.Id == id);
var lst = new List<IEnumerable>
{
q.FetchMany(x => x.Characters).ToFuture(),
q.Fetch(x=>x.UpdateableData).ToFuture(),
session.QueryOver<User>().Where(x => x.Id == id)
.Fetch(x=>x.Characters).Eager
.Fetch(x => x.Characters.First().SmartChallengeTrackers).Eager
.Future()
};
var r = session.QueryOver<User>().Where(x => x.Id == id)
.TransformUsing(Transformers.DistinctRootEntity)
.Future();
foreach (IEnumerable el in lst)
{
foreach (object o in el)
{
}
}
return r.ToArray();
它仍然比在一个查询中加入所有内容要好 - NHibernate 不必解析由 join x join x join x join 引入的数千行...
您可以将正常的 select 查询(没有 Fetch
)添加到同一批次,但它们不会用于检索另一个实体的集合。
我有 "static" 个只读实体,我只是用 QueryOver<T>().List<T>()
加载它们。他们所有的属性都不是"lazy"。所以他们中的一些人有N+1问题。
我尝试使用Future
来避免N+1。但看起来 NH 将实体属性视为 "lazy"。当我访问它们时,它甚至会从数据库中一个一个地重新加载实体(导致相同的 N+1 情况),尽管所有实体都是初步预加载的并且应该缓存在会话一级缓存中。这是我的代码:
var futures = new List<IEnumerable>();
futures.Add(s.QueryOver<DailyBonus>().Future<DailyBonus>());
futures.Add(s.QueryOver<DailyBonusChestContent>().Future<DailyBonusChestContent>());
// ... other entities ...
// all queries should be sent with first enumeration
// but I want to ensure everything is loaded
// before using lazy properties
foreach (IEnumerable future in futures)
{
if (future.Cast<object>().Any(x => false)) break;
}
// now everything should be in cache, right?
// so I can travel the whole graph without accessing db?
Serializer.Serialize(ms, futures); // wow, N+1 here!
我使用 hibernatingrhinos 分析器检查了此行为。
那么这是怎么回事?
使用 futures 加载带有集合的实体的唯一正确方法是 Fetch
,这意味着每个查询的连接:
var q = session.Query<User>().Where(x => x.Id == id);
var lst = new List<IEnumerable>
{
q.FetchMany(x => x.Characters).ToFuture(),
q.Fetch(x=>x.UpdateableData).ToFuture(),
session.QueryOver<User>().Where(x => x.Id == id)
.Fetch(x=>x.Characters).Eager
.Fetch(x => x.Characters.First().SmartChallengeTrackers).Eager
.Future()
};
var r = session.QueryOver<User>().Where(x => x.Id == id)
.TransformUsing(Transformers.DistinctRootEntity)
.Future();
foreach (IEnumerable el in lst)
{
foreach (object o in el)
{
}
}
return r.ToArray();
它仍然比在一个查询中加入所有内容要好 - NHibernate 不必解析由 join x join x join x join 引入的数千行...
您可以将正常的 select 查询(没有 Fetch
)添加到同一批次,但它们不会用于检索另一个实体的集合。