为什么未在会话一级缓存中缓存期货?

时间:2015-10-28 22:30:42

标签: c# hibernate caching nhibernate future

我有&#34;静电&#34;我只是用QueryOver<T>().List<T>()加载的只读实体。他们所有的财产都不是懒惰的&#34;。所以他们中的一些人有N + 1问题。

我尝试使用Future来避免N + 1。但看起来NH认为实体属性为&#34;懒惰&#34;。当我访问它们时,它甚至会逐个从db重新加载实体(导致相同的N + 1情况),尽管所有实体都是预先加载的,应该缓存在会话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 profiler检查了这种行为。

那么这里出了什么问题?

1 个答案:

答案 0 :(得分:0)

使用期货加载具有集合的实体的唯一正确方法是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 ...引入的数千行...

您可以将常规选择查询(不包含Fetch)添加到同一批次,但不会将其用于检索其他实体上的集合。