使用 ActiveRecord 在 nHibernate 中急切加载延迟加载的实体

发布于 2024-07-10 18:41:53 字数 1254 浏览 8 评论 0原文

我正在开发一个项目,该项目具有丰富的对象模型和各种聚合根集。

我们使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

勿忘初心 2024-07-17 18:41:53

对 Account.Order.Product 实体执行“内部联接获取”。 因此,不要像这样(这可能是您已经拥有的):

"from Account a inner join fetch a.Order where a.ID = ?"

告诉它也获取 Order.Product:

"from Account a inner join fetch a.Order inner join fetch a.Order.Product where a.ID = ?"

Do an "inner join fetch" on the Account.Order.Product entity. So instead of something like this (which is what you probably already have):

"from Account a inner join fetch a.Order where a.ID = ?"

Tell it to fetch the Order.Product as well:

"from Account a inner join fetch a.Order inner join fetch a.Order.Product where a.ID = ?"
神仙妹妹 2024-07-17 18:41:53

为什么你想要急切的行为?

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.

囍孤女 2024-07-17 18:41:53

来自“NHibernate in Action”,第 225 页:

NHibernate 目前限制您只能急切地获取一个集合。

这可以解释用于获取地址的第二个查询。

From "NHibernate in Action", page 225:

NHibernate currently limits you to fetching just one collection eagerly.

That might explain the second query for fetching the addresses.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文