【问题标题】:NHIbernate "References" Property generating Select + 1 even though correctly OUTER JOININGNHIbernate“参考”属性生成 Select + 1 即使正确 OUTER JOINING
【发布时间】:2013-03-20 14:29:01
【问题描述】:

好的,我对这个 NHibernate 查询有点困惑。困惑在于 PasswordResetToken。

首先,这是映射:

public ContactMap()
    {
        Table("Contact");
        Id(x => x.ContactId, "ContactId").Unique().GeneratedBy.Increment();
        Map(x => x.EmailAddress);
        ...
        Map(x => x.JobTitle);

        References(x => x.PasswordResetToken, "EmailAddress")
            .PropertyRef(x => x.EmailAddress)
            .Cascade.None()
            .Not.LazyLoad()
            .Not.Update();


        HasMany(x => x.Roles)
            .Table("tblContactRole").KeyColumn("ContactId").Element("Role", part => part.Type<global::NHibernate.Type.EnumStringType<ContactRoles>>())
            .AsSet()
            .Not.LazyLoad();
    }

现在是查询:

public IList<Contact> GetContacts(int id)
    {
        var contacts = Session.CreateCriteria<Contact>()
                           .Add(Restrictions.Eq("Id", id))
                           .Add(Restrictions.Eq("IsActive", true))
                           .SetFetchMode("Roles", FetchMode.Eager)
                           .SetFetchMode("PasswordResetToken", FetchMode.Eager)
                           .SetResultTransformer(CriteriaSpecification.DistinctRootEntity)
                           .List<Contact>();

        return contacts;
    }

我的理解是 FetchMode.Eager 意味着使用 JOIN 而不是 SUBSELECT,因此没有任何理由出现对 db 的额外调用。

运行一个正确的 SQL 查询,返回所有需要为联系人提供水合的信息,这从 NHProf 的屏幕截图(突出显示的查询)可以看出(不要担心不同的表名等 - 我已经清理了上面的代码):

我不明白为什么会生成并运行对 PasswordResetToken 表的数十个单独选择?其中一个查询仅针对没有 PasswordResetToken 的每个联系人生成(即第一个查询为这些列返回空值) - 不确定这与它有什么关系。

一个联系人可能有也可能没有几个角色(对于这个问题是多余的),同样,可能有也可能没有一个 PasswordResetToken。

数据库有点狡猾,外键很少。在这种情况下,Contact 和 PasswordResetToken 之间的链接是一个简单的共享列“EmailAddress”。

所有这些查询都是在运行上述单行代码时生成的(即,该代码不在循环中)。

如果我遗漏任何信息,请告诉我。

我应该在谷歌上搜索什么?

【问题讨论】:

    标签: nhibernate fluent-nhibernate-mapping


    【解决方案1】:

    这是bug。我会尝试让它只处理两个查询,尽管从错误报告中听起来这将是一个挑战。

    附加的测试表明,引用唯一属性(而不是 Id)的多对一关联会导致选择 n+1 问题。虽然第一条语句包含了正确的连接,但是所有关联的实体都是在连接选择之后一个接一个地取出来的。 (在唯一列中具有相同值的实体甚至会被多次获取。)

    有趣的一点是,这个错误只有在被引用的情况下才会发生 实体已经在会话缓存中。如果他们不是,没有 额外的选择语句被创建。

    【讨论】:

    • 我今天也自己打了这个! Spooky,我只是对 bug 投了赞成票,所以我们得到的越多,修复它的机会就越大。
    • 感谢 Jamie - 永远不会猜到这是一个错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-12
    相关资源
    最近更新 更多