使用 ActiveRecord 在 nHibernate 中急切加载延迟加载的实体
我正在开发一个项目,该项目具有丰富的对象模型和各种聚合根集。
我们使用 Castle 堆栈(Monorail 通过 ActiveRecord 到 nHibernate)。
我们已将聚合根标记为惰性[ActiveRecord(Lazy = true)]
,并在我们的存储库上定制了“热切”例程以热切获取对象图。 我们使用 HQL 来定义从根的子集合中快速获取,
例如,如果 Account
是聚合根(并标记为延迟加载),我们将立即获取 Account .. Order .. Product完整图的实体。
所以到目前为止没有什么意外(希望如此)。
现在,如果在上面的示例中,Product 也被标记为 [ActiveRecord(Lazy = true)]
,这似乎会停止 HQL 中的 eager fetch 指令。
有谁知道一种方法来强制急切获取延迟加载的子对象?
干杯 ian
更新:
好的,这里有一些示例 hql,使用下面“me.yahoo.com/../1”中的示例,我们使用 IMuliQuery 在获取多个数据时重新处理 N+1 依赖项 -一对多关系。 我们还明确使用多对多映射类。 结果我们的 hql 是:
from Account a 'm eager loading the graph
inner join fetch a.AccountsOrders ao
inner join fetch ao.Order
from Account a 'm eager loading the graph
inner join fetch a.AccountAddresses aa
inner join fetch aa.Address ad
where a.ID = ?
...所以这会执行 2 个 sql 语句并返回所需的最小行集,我们可以将其解析为单个对象图。 好的。
但是...如果 Address
被标记为延迟加载(而 Order
没有),则访问 Order
不会触发进一步的加载sql 语句,但访问 Address
确实如此,尽管事实上两者都是急切加载的。
那么为什么上面的延迟加载实体 Address
没有被上面的语句急切地获取呢?
I'm working on a project that has a rich object model with various sets of aggregate roots.
We're using the Castle stack (Monorail through to nHibernate with ActiveRecord).
We have marked the aggregate roots as lazy [ActiveRecord(Lazy = true)]
and have customized 'eager' routines on our Repository to eager fetch an object graph. We use HQL to define eager fetches from our child collection of our root,
e.g. if Account
is the aggregate root (and marked lazy loaded) we'll eager fetch Account .. Order .. Product
entities for a complete graph.
So no surprises so far (hopefully).
Now if in the above example, Product is also marked [ActiveRecord(Lazy = true)]
, this seems to stop the eager fetch directive in the HQL.
Does anyone know a way to force the eager fetch of a lazy loaded child object ??
Cheers
ian
Update:
Ok here's some example hql, Using the example from 'me.yahoo.com/../1' below, we're using IMuliQuery to reslove N+1 dependencies when fetching over many-to-many relationships. We're also explicitly using many-to-many mapping classes. As a result our hql is:
from Account a 'm eager loading the graph
inner join fetch a.AccountsOrders ao
inner join fetch ao.Order
from Account a 'm eager loading the graph
inner join fetch a.AccountAddresses aa
inner join fetch aa.Address ad
where a.ID = ?
... so this executes the 2 sql statements and returns the required minimal rowset, and we can resolve this down into a single object graph. Nice.
But... if, say, Address
was marked lazy loaded (and Order
wasn't), accessing Order
doesn't trigger a further sql statements, yet accessing Address
does, despite the fact both are eager loaded.
So why isn't the lazy loaded entity Address
, above, eager fetched by the above statement?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
对 Account.Order.Product 实体执行“内部联接获取”。 因此,不要像这样(这可能是您已经拥有的):
告诉它也获取 Order.Product:
Do an "inner join fetch" on the Account.Order.Product entity. So instead of something like this (which is what you probably already have):
Tell it to fetch the Order.Product as well:
为什么你想要急切的行为?
ActiveRecord 中的所有关系属性都有一个“Lazy=”参数来告诉 ActiveRecord 延迟加载相关对象。 除“属于”之外的所有内容。 BelongsTo 检查依赖对象的 ActiveRecord 属性中是否有 Lazy=true,然后为该对象创建代理,而不是执行选择或联接。
为了使延迟加载工作,类实例的所有方法和属性都需要标记为虚拟。 这允许 ActiveRecord 构造动态代理类。
现在,获取完整的图表以提高性能听起来可能是个好主意,但实际上它可能会更慢。 我有 3 个充分的理由:
1.)BelongsTo 有一个 Fetch 选项来定义如何拉取相关对象。 FetchEnum.Join 强制 AR 使用 Join。 获取枚举。 Select 强制 AR 对每个对象使用单独的 select 语句。 连接速度很慢,我们发现切换到单独选择后性能提高了 10 倍。 Lazy=true + FetchEnum.Select 和 eager 之间的客户端代码没有任何实际差异。
2.) NHibernate 进行缓存。 如果该对象已缓存在会话或二级缓存中,则可以从那里加载该对象并避免额外的工作。
3.) 如果您没有引用对象图的一部分,您将错过延迟加载的任何好处。 同样,你会做比必要的更多的工作。
Why do you want the eager behavior?
All of the Relationship attributes in ActiveRecord have a 'Lazy=' parameter to tell ActiveRecord to lazy load the related object. All except BelongsTo. BelongsTo checks if the dependent object has Lazy=true in its ActiveRecord attribute and then creates a proxy for the object instead of doing a select or join.
For Lazy loading to work all methods and properties of the class instance need to be marked as virtual. This allows ActiveRecord to construct a dynamic proxy class.
Now it may sound like a good idea to fetch the complete graph for performance but in practice its probably slower. I have 3 good reasons why:
1.) BelongsTo has a Fetch option to define how related objects are pulled. FetchEnum.Join forces AR to use a Join. FetchEnum. Select forces AR to use separate select statements for each object. Joins are slow, we see a 10x performance improvement from switching to individual selects. There is no effectual difference in the client code between Lazy=true + FetchEnum.Select and eager.
2.) NHibernate does caching. If the object is already cached in the session or in the Level 2 cache it can be loaded form there and avoid the extra work.
3.) You would miss out on any benefits of lazy loading in cases where you didn't reference part of the object graph. Again you would do more work than necessary.
来自“NHibernate in Action”,第 225 页:
这可以解释用于获取地址的第二个查询。
From "NHibernate in Action", page 225:
That might explain the second query for fetching the addresses.