NHibernate - 三个类之间的三个双向关系给出 N+1

发布于 2024-11-19 05:15:00 字数 1822 浏览 2 评论 0原文

我有一个有点复杂的形成三角形的对象模型。 User 实体包含 ItemsTaxonomies 的集合。 Item 也有分类法。为了方便起见,我希望 ItemTaxonomy 了解其所有者,并 Taxonomy 了解其 Item(如果有) 。参见图表:

diagram

因此,这形成了三个双向关系。我的问题是,当我像这样在 NHibernate 中映射它并询问具有给定 ID 的用户时,我得到 Select N+1 问题。

首先,User 加载了急切获取的Items。然后,Taxonomies 会加载急切获取的Item 连接到它。这符合预期并符合映射中的定义。但现在有 N+1 个查询来加载与 Taxonomies 相关的 Items

queries

这是多余的,因为对象图的所有部分都已加载。当我从 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:

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.

queries

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 技术交流群。

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

发布评论

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

评论(1

佞臣 2024-11-26 05:15:00

因为映射会影响所有查询,所以我喜欢遵循这样的规则:只有当一个实体在没有其他实体的情况下永远没有用处时,才应将映射更改为急切加载。在您的情况下,如果您只想要用户,而不关心项目和分类记录,那么您将做额外的数据库工作,但没有任何好处。

我建议您在查询中通过其他路线执行急切加载。

Session.QueryOver<User>().Where(u => u.Id == 1)
    .join.QueryOver<Items>(u => u.Items)
    .Join.QueryOver<Taxonomy>(i => i.Taxonomy)
    .TransformUsing(Trasnformers.DistinctRootEntity);

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.

Session.QueryOver<User>().Where(u => u.Id == 1)
    .join.QueryOver<Items>(u => u.Items)
    .Join.QueryOver<Taxonomy>(i => i.Taxonomy)
    .TransformUsing(Trasnformers.DistinctRootEntity);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文