渴望用NHibernate加载子属性和孙子

时间:2017-06-28 18:55:21

标签: c# nhibernate fetch eager-loading linq-to-nhibernate

我有一个类模型图,如下所示

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。

2 个答案:

答案 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个查询,但它也可以工作。