【问题标题】:Loading complex graph in nhibernate在 nhibernate 中加载复杂图形
【发布时间】:2015-02-27 04:52:32
【问题描述】:

想象一下,我有非常复杂的模型图,例如:

Orchestra -> Musicians -> Instruments -> Properties
                                      -> Items
                       -> Songs -> Parts

我理论上知道 Futures 是如何工作的,但是我如何加载这个完整的图表让我们说一个具体的音乐家(由 id 指定)。

我知道对于同一级别的每个集合,我必须创建一个简单的未来查询,以避免在同一查询中出现笛卡尔积。 所以当我执行这样的代码时:

using(var session = GetSession()){
    var instrumentQuery = session.QueryOver<Musicians>()
         .Where(x=>x.Id == CONCRETEMUSICIANIDTHERE)
         .JoinQueryOver<Instruments>(x=>x.Instruments)                     
         .Future();
    var instrumentProperties = = session.QueryOver<Musicians>()
         .Where(x=>x.Id == CONCRETEMUSICIANIDTHERE)
         .JoinQueryOver<Instrument>(x=>x.Instruments, ()=> instrumentAlias)
         .JoinQueryOver<Property>(()=>instrumentAlias.Properties)
         .Future();
     var instrumentItems = = session.QueryOver<Musicians>()
         .Where(x=>x.Id == CONCRETEMUSICIANIDTHERE)
         .JoinQueryOver<Instrument>(x=>x.Instruments, ()=> instrumentAlias)
         .JoinQueryOver<Item>(()=>instrumentAlias.Items)
         .Future();
    ...
    ...CONTINUE same future queries for each unique collection       
    ...

    ...
    var result = session.QueryOver<Musician>()
         .Where(x=>x.Id == CONCRETEMUSICIANIDTHERE)
         .SingleOrDefault<Musician>(); //This query is not future so it should???? load all futures ???

    return result;

}

但即使最后一个查询不是将来的,它也不会将那些 FUTUR..ISH 查询发送到 DB(我用 SQL 分析器检查过......没有这样的 SQL 标题到 DB)

musician.instrument 仍然抛出延迟初始化异常。

此代码仅是演示性的,纯属理论性的。

我要避免的是:

  • 使用 HQL(我讨厌那些神奇的字符串...)
  • 更改映射以急切地加载所有内容,因为有些用例我只需要音乐家和乐器? (或任何其他子集)
  • 在这里避免 N+1 查询问题
  • 让会话打开太久,因为这些数据可能会从其他服务器实例更改

我想要达到的目标

  • 强制 nhibernate 根据提供的标准正确地创建和构造对象结构。

  • 强制 nhibernate 仅对此查询使用 fetch select

还有一个类似的问题: How to load a large, complex object graph using NHibernate

答案是……改变你的映射……这是我不想要的,因为我看不到为每次使用转换加载这个复杂图表的点(即使是简单的)

技术背景:

  • 我们使用 Nhibernate 4.0
  • 作为数据库,可能会使用 Azure DB 或 SQL Server(或者可能是 postgreSQL)

【问题讨论】:

    标签: c# nhibernate future


    【解决方案1】:

    我会说,这里的方式是

    • 使用Fetch 代替JoinQuery
    • 也将最终结果放入Future

    所以这将是更新后的 sn-p:

    var instrumentQuery = session.QueryOver<Musicians>()
         .Where(x=>x.Id == CONCRETEMUSICIANIDTHERE)
         .Fetch(x=>x.Instruments).Eager
         .Future();
    var instrumentProperties = = session.QueryOver<Musicians>()
         .Where(x=>x.Id == CONCRETEMUSICIANIDTHERE)
         .Fetch(x=>x.SecondCollection).Eager
         .Future();
    
    ...
    ...CONTINUE same future queries for each unique collection       
    ...
    
    ...
    var result = session.QueryOver<Musician>()
         .Where(x=>x.Id == CONCRETEMUSICIANIDTHERE)
         // all will be fetaures
         .Future()
         .SingleOrDefault<Musician>();
    

    注意:我会走不同的路。仅加载根对象(音乐家)。使用batch-size 优化获取。在会话打开时创建 DTO。

    【讨论】:

    • 你确定吗? ......Fetch(x=>x.Instruments, ()=>InstrumentAlias).Eager.Fetch(()=>instrumentAlias.Properties).Eager.....这会不会在仪器和属性上创建笛卡尔积?
    • 一般来说:我敢肯定,我永远不会走这条路。我会懒惰地加载所有东西(请参阅我的链接)并创建 DTO 或序列化对象。没有明确的 Fetching。只需batch-fetching 即可避免 1 + N。对于您的问题:-我测试的上述示例......也许......可能只有一个对象以这种方式获取......所以我更新了问题。它应该显示的内容:我们可以使用 Fetch eager 和 Future 来表示所有的集合......以及 Future 来表示根实体的 SingleOrDefault。但我会使用batch-fetching
    • 是的,但我真的想在一次查询中将我需要的所有内容(仅我需要的内容)加载到数据库,因为数据可能非常活跃并且会发生变化......这意味着我必须设置相当大的隔离模式 - 可序列化到对数据库有高性能影响的会话。在这种情况下,我们也没有 DTO。这只是关于服务内部工作和实体更改。
    • 那么我试图展示的东西会起作用。创建尽可能多的 Fetch、Eager、Future 和你拥有的所有集合。然后将根实体也放入 Future 并触摸它。全部都将一次性加载...我测试过
    • 好的,谢谢,执行正常查询时没有命中期货有点奇怪。我会将此标记为答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-27
    • 1970-01-01
    • 2013-01-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多