Session.Get 即使在 lazy=false 时也以 N+1 加载
Session.Get loads with N+1 even when lazy=false
我有这样的实体:
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<User>()
我看到这样的查询:
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<User>
时让 NHibernate 第二次加载字符,我想避免!
我用过期货:
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();
我有这样的实体:
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<User>()
我看到这样的查询:
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<User>
时让 NHibernate 第二次加载字符,我想避免!
我用过期货:
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();