在 nhibernate 中加载复杂图形
Loading complex graph in nhibernate
想象一下,我有一个非常复杂的模型图,例如:
Orchestra -> Musicians -> Instruments -> Properties
-> Items
-> Songs -> Parts
理论上我知道 Futures 是如何工作的,但是我如何加载这个完整的图表让我说一个具体的音乐家(由 id 指定)。
我知道对于同一级别的每个 collection 我必须创建一个简单的未来查询以避免同一查询中的笛卡尔积。
所以当我执行这样的代码时:
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 查询发送到数据库(我用 SQL 分析器检查过......没有这样的 SQL 标题到数据库)
musician.instrument 仍然抛出惰性初始化异常。
此代码只是演示性的,纯理论性的。
我要避免的是:
- 使用 HQL(我讨厌那些神奇的字符串...)
- 更改映射以急切地加载所有内容,因为有些用例我只需要音乐家和乐器? (或任何其他子集)
- 在这里避免 N+1 查询问题
- 让 session 打开太久,因为这些数据可能会从其他服务器实例更改
我想要达到的目标
- 要么强制 nhibernate 根据提供的条件正确地创建和构造 object 结构。
或
- 强制 nhibernate 仅对该查询使用 fetch select
还有一个类似的问题:
How to load a large, complex object graph using NHibernate
答案是……改变你的映射……我不想要,因为我看不到为每次使用转换加载这个复杂图形的点(即使是简单的转换)
技术背景:
- 我们使用 Nhibernate 4.0
- 作为数据库,可能会使用 Azure 数据库或 SQL 服务器(或者可能会使用 postgreSQL)
我会说,这里的方式是
- 使用
Fetch
而不是 JoinQuery 和
- 将最终结果也放入
Future
所以这将是更新后的代码段:
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。
想象一下,我有一个非常复杂的模型图,例如:
Orchestra -> Musicians -> Instruments -> Properties
-> Items
-> Songs -> Parts
理论上我知道 Futures 是如何工作的,但是我如何加载这个完整的图表让我说一个具体的音乐家(由 id 指定)。
我知道对于同一级别的每个 collection 我必须创建一个简单的未来查询以避免同一查询中的笛卡尔积。 所以当我执行这样的代码时:
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 查询发送到数据库(我用 SQL 分析器检查过......没有这样的 SQL 标题到数据库)
musician.instrument 仍然抛出惰性初始化异常。
此代码只是演示性的,纯理论性的。
我要避免的是:
- 使用 HQL(我讨厌那些神奇的字符串...)
- 更改映射以急切地加载所有内容,因为有些用例我只需要音乐家和乐器? (或任何其他子集)
- 在这里避免 N+1 查询问题
- 让 session 打开太久,因为这些数据可能会从其他服务器实例更改
我想要达到的目标
- 要么强制 nhibernate 根据提供的条件正确地创建和构造 object 结构。
或
- 强制 nhibernate 仅对该查询使用 fetch select
还有一个类似的问题: How to load a large, complex object graph using NHibernate
答案是……改变你的映射……我不想要,因为我看不到为每次使用转换加载这个复杂图形的点(即使是简单的转换)
技术背景:
- 我们使用 Nhibernate 4.0
- 作为数据库,可能会使用 Azure 数据库或 SQL 服务器(或者可能会使用 postgreSQL)
我会说,这里的方式是
- 使用
Fetch
而不是 JoinQuery 和 - 将最终结果也放入
Future
所以这将是更新后的代码段:
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。