我有一个类模型图,如下所示
A { ISet<B> Bset; int Id;}
B { ISet<C> Cset; D Dprop; }
D { int Id; }
所有属性都配置为延迟加载。我试图编写一个查询来加载所有图表,从A开始。理想情况下,它会像
一样var result = (from conf in s.Query<A>()
.FetchMany(x => x.Bset)
.ThenFetch(x => x.Dprop)
// line below doesn't work, because x
//is a D object here, and not a "B", as I would like
.ThenFetchMany(x => x.Cset)
where conf.Id == 42
select conf).SingleOrDefault();
所以我需要做的是&#34;上一层&#34;当我尝试获取Cset关联时。有谁知道怎么做?
我正在使用Nhibernate 4.1.0。
答案 0 :(得分:1)
您必须重新开始使用FetchMany
。
var result = (from conf in s.Query<A>()
.FetchMany(x => x.Bset)
.ThenFetch(x => x.Dprop)
.FetchMany(x => x.Bset)
.ThenFetchMany(x => x.Cset)
where conf.Id == 42
select conf).SingleOrDefault();
但是我担心这会导致笛卡尔积,重复结果和/或导致糟糕的表现。
更好地切换到延迟加载。通过enabling batch loading of lazy loads避免N + 1选择问题。
如果您需要关闭会话然后使用您的实体,则必须通过在其延迟加载的属性上调用NHibernateUtil.Initialize()
来触发延迟加载,并在您的实体上循环。由于延迟加载批处理,它不会对已经加载的任何内容执行任何操作
另一种选择是在关闭会话之前将您的实体转换为视图模型。
答案 1 :(得分:0)
Frédréric回答说,一种方法是重复FetchMany子句,从(从图中的第一个实体开始)再次到达Cset:
var result = (from conf in s.Query<A>()
.FetchMany(x => x.Bset).ThenFetch(x => x.Dprop)
.FetchMany(x => x.Bset).ThenFetchMany(x => x.Cset)
where conf.Id == 42
select conf).SingleOrDefault();
使用集合进行关联,此解决方案不会在生成的SQL中生成笛卡尔积,也不会在NHibernate返回的对象中生成笛卡尔积。
另一个解决方案是使用 Future Query ,它将在实际查询被触发时(就在它之前)执行:
var queryAux = (from conf in s.Query<A>()
.FetchMany(x => x.Bset)
.ThenFetch(x => x.Dprop)
where conf.Id == 42 select conf).ToFuture();
var result = (from conf in s.Query<A>()
.FetchMany(x => x.Bset)
.ThenFetch(x => x.Dprop)
where conf.Id == 42
select conf).SingleOrDefault();
这样,将向数据库触发2个查询,但它也可以工作。