NHibernate - 三个类之间的三个双向关系给出 N+1
我有一个有点复杂的形成三角形的对象模型。 User
实体包含 Items
和 Taxonomies
的集合。 Item
也有分类法。为了方便起见,我希望 Item
和 Taxonomy
了解其所有者,并 Taxonomy
了解其 Item
(如果有) 。参见图表:
因此,这形成了三个双向关系。我的问题是,当我像这样在 NHibernate 中映射它并询问具有给定 ID 的用户时,我得到 Select N+1 问题。
首先,User
加载了急切获取的Items
。然后,Taxonomies
会加载急切获取的Item
连接到它。这符合预期并符合映射中的定义。但现在有 N+1 个查询来加载与 Taxonomies
相关的 Items
。
这是多余的,因为对象图的所有部分都已加载。当我从 User
端使我的 User-Item
关系单向时,问题就消失了(如预期的那样,只有 2 个查询),但我不想删除向后的关系关系。 是否可以对所有三个关系进行最佳双向获取?
以下是我的映射部分:
public class UserOverride : IAutoMappingOverride<User>
{
public void Override(AutoMapping<User> mapping)
{
mapping.HasMany(x => x.Items).Inverse()
.Not.LazyLoad().Fetch.Join();
mapping.HasMany(x => x.Taxonomies).Inverse()
.LazyLoad().Fetch.Select();
}
}
public class ItemOverride : IAutoMappingOverride<Item>
{
public void Override(AutoMapping<Item> mapping)
{
mapping.References(x => x.Taxonomy); // many-to-one
}
}
public class TaxonomyOverride : IAutoMappingOverride<Taxonomy>
{
public void Override(AutoMapping<Taxonomy> mapping)
{
mapping.HasOne(x => x.Item).PropertyRef(x => x.Taxonomy)
.Not.LazyLoad().Fetch.Join();
}
}
并且我以最简单的方式查询数据库:
var user = session.Get<User>(1);
I'm having bit complicated object model that forms a triangle. There is User
entity that has collections of Items
and Taxonomies
. Item
has a taxonomy, too. And for convenience, I wanted Item
and Taxonomy
to know its owner and Taxonomy
to know its Item
, if any. See diagram:
So this makes three bi-directional relations. My problem is when I map it in NHibernate like that and asking for user with given ID, I'm getting Select N+1 problem.
At first, User
is loaded with eagerly fetched Items
. Then Taxonomies
are loaded with eagerly fetched Item
connected to it. And this is as expected and as defined in mappings. But now there is N+1 queries to load Items
related with Taxonomies
.
This is redundant as all parts of object graph was already loaded. Thie problem disappears when I make my User-Item
relation unidirectional from User
side (there are only 2 queries, as expected), but I don't want to remove that backward relationship. Is it possible to have optimal fetching with all three relations bidirectional?
Here are my mapping parts:
public class UserOverride : IAutoMappingOverride<User>
{
public void Override(AutoMapping<User> mapping)
{
mapping.HasMany(x => x.Items).Inverse()
.Not.LazyLoad().Fetch.Join();
mapping.HasMany(x => x.Taxonomies).Inverse()
.LazyLoad().Fetch.Select();
}
}
public class ItemOverride : IAutoMappingOverride<Item>
{
public void Override(AutoMapping<Item> mapping)
{
mapping.References(x => x.Taxonomy); // many-to-one
}
}
public class TaxonomyOverride : IAutoMappingOverride<Taxonomy>
{
public void Override(AutoMapping<Taxonomy> mapping)
{
mapping.HasOne(x => x.Item).PropertyRef(x => x.Taxonomy)
.Not.LazyLoad().Fetch.Join();
}
}
And I query my database the simplest possible way:
var user = session.Get<User>(1);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
因为映射会影响所有查询,所以我喜欢遵循这样的规则:只有当一个实体在没有其他实体的情况下永远没有用处时,才应将映射更改为急切加载。在您的情况下,如果您只想要用户,而不关心项目和分类记录,那么您将做额外的数据库工作,但没有任何好处。
我建议您在查询中通过其他路线执行急切加载。
Because mappings will effect all queries, I like to live by the rule that mappings should only be changed to eagerly load if an entity is NEVER useful without an other entity. In your situation, if you ever just want Users, and could care less about the Item and the Taxonomy records, you will be doing extra database work for no benefit.
I would advise you perform the eager loading via the other route- in your query.