【问题标题】:Session.Get loads with N+1 even when lazy=falseSession.Get 即使在lazy=false 时也会加载 N+1
【发布时间】:2016-11-10 21:04:49
【问题描述】:

我有这样的实体:

public class User
{
     public virtual int Id { get; set;}
    public virtual Iesi.Collections.Generic.ISet<Character> Characters { get; set; }
}

public class Character
{
     public virtual int Id { get; set;}
     public virtual User User { get; set;}
    public virtual Iesi.Collections.Generic.ISet<UserCharacterSmartChallengeTracker> SmartChallengeTrackers { get; set; }
}

public class UserCharacterSmartChallengeTracker
{
    public virtual int Id { get; set; }
    public virtual int? CharacterId { get; set; }
}

它们都不是延迟加载的。

当我session.Get&lt;User&gt;() 时,我看到这样的查询:

SELECT smartchall0_.character_id                   as character3_1_,
       smartchall0_.id                             as id1_,
       smartchall0_.id                             as id51_0_,
       smartchall0_.character_id                   as character3_51_0_,
FROM   public.user_character_smart_challenge_trackers smartchall0_
WHERE  smartchall0_.character_id = 48176 /* :p0 */

SELECT smartchall0_.character_id                   as character3_1_,
       smartchall0_.id                             as id1_,
       smartchall0_.id                             as id51_0_,
       smartchall0_.character_id                   as character3_51_0_,
FROM   public.user_character_smart_challenge_trackers smartchall0_
WHERE  smartchall0_.character_id = 48175 /* :p0 */

-- and others

我尝试将它们全部预加载到会话缓存中:

 var ids = session.Query<Character>().Where(x => x.User.Id == id)
            .Select(x => x.Id)
            .ToArray();
 session.Query<UserCharacterSmartChallengeTracker>().Where(x => ids.Contains(x.Id)).ToArray();

有查询

select character0_.id as col_0_0_
from   public.characters character0_
where  character0_.user_id = 9602 /* :p0 */
select usercharac0_.id                             as id51_,
       usercharac0_.character_id                   as character3_5
from   public.user_character_smart_challenge_trackers usercharac0_
where  usercharac0_.id in (48176 /* :p0 */, 48175 /* :p1 */, 48174 /* :p2 */, 48173 /* :p3 */,
                           48172 /* :p4 */, 48171 /* :p5 */, 48170 /* :p6 */, 48169 /* :p7 */)

但是 NHibernate 忽略了它们都已经加载到会话缓存中并生成相同的 N+1 查询这一事实!如何解决这个问题?


更新:预加载

session.QueryOver<Character>().Where(x => x.User.Id == id)
                .Fetch(x => x.User).Lazy
                .Fetch(x=>x.SmartChallengeTrackers).Eager
                .List();

删除 N+1 但在我想避免 session.Get&lt;User&gt; 时使 NHibernate 第二次加载字符!

【问题讨论】:

  • 您是否查看过文档中的这一部分 (nhibernate.info/doc/nh/en/…)?
  • 我的理解是预加载不会影响NH生成的查询,只影响它是否需要完全水合对象或者只是从一级缓存中获取。
  • 你真的要使用 session.Get 吗?为什么不编写一个投影到某个对象的查询,这样您就不会每次都加载整个对象图?
  • @Fran 我需要整个图表

标签: c# nhibernate eager-loading fetching-strategy select-n-plus-1


【解决方案1】:

我用过期货:

        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();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多