ActiveRecord (NHibernate) 急切加载错误?

发布于 2024-11-08 13:02:26 字数 2687 浏览 0 评论 0原文

我有两个类:FileApplicant,我正在使用 ActiveRecord 3.0 RC (NHibernate 3.1.0.4000)。

文件

[ActiveRecord("`File`", Lazy = true)]
public class File : TestProDb<File> {

    [PrimaryKey("`Id`")]
    public virtual long Id { get; private set; }

    [Property("`Name`")]
    public virtual string Name { get; set; }

    [HasMany(Cascade = ManyRelationCascadeEnum.AllDeleteOrphan, Inverse = true, Lazy = true)]
    public virtual IList<Applicant> Applicants { get; set; }

    public File() {
        this.Applicants = new List<Applicant>();
    }
}

申请人

[ActiveRecord("`Applicant`", Lazy = true)]
public class Applicant : TestProDb<Applicant> {

    [PrimaryKey("`Id`")]
    public virtual long Id { get; private set; }

    [Property("`Surname`")]
    public virtual string Surname { get; set; }

    [BelongsTo(Column = "IdFile", Lazy = FetchWhen.OnInvoke)]
    public virtual File File { get; set; }
}

现在我想根据一些申请人条件选择文件。结果文件应包含急切加载的申请人

using (new SessionScope()) {
    DetachedCriteria fileQuery = DetachedCriteria.For<File>();
    fileQuery.SetResultTransformer(new DistinctRootEntityResultTransformer());
    fileQuery.SetFetchMode("Applicants", NHibernate.FetchMode.Eager);
    fileQuery.CreateCriteria("Applicants").Add(Expression.Like("Surname", "a", MatchMode.Anywhere));

    IList<File> files = File.FindAll(fileQuery);
    foreach (File file in files) {
        foreach (Applicant applicant in file.Applicants) {
            Console.WriteLine(applicant.Surname);
        }
    }
}

来自 NHProof - 我执行 FindAll 时的第一个查询FindAll

SELECT this_.[Id]            as Id1_0_1_,
   this_.[Name]          as Name2_0_1_,
   applicant1_.[Id]      as Id1_1_0_,
   applicant1_.[Surname] as Surname2_1_0_,
   applicant1_.IdFile    as IdFile1_0_
FROM   [File] this_
   inner join [Applicant] applicant1_
     on this_.[Id] = applicant1_.IdFile
WHERE  applicant1_.[Surname] like '%a%' /* @p0 */

来自 NHProof - 循环中的第二个查询 Console.WriteLine(applicant.Surname)

SELECT applicants0_.IdFile    as IdFile1_,
   applicants0_.[Id]      as Id1_1_,
   applicants0_.[Id]      as Id1_1_0_,
   applicants0_.[Surname] as Surname2_1_0_,
   applicants0_.IdFile    as IdFile1_0_
FROM   [Applicant] applicants0_
WHERE  applicants0_.IdFile = 1 /* @p0 */

为什么每个申请人循环(第二个查询示例)都会获得到数据库的额外往返?由于 FetchMode.Eager,总共应该只有一个数据库查询。我对此完全困惑。我什至尝试删除 virtual 关键字并将所有惰性值设置为 false。还是一样。这是一个错误吗?

I have two classes: File, Applicant and I'm using ActiveRecord 3.0 RC (NHibernate 3.1.0.4000).

File

[ActiveRecord("`File`", Lazy = true)]
public class File : TestProDb<File> {

    [PrimaryKey("`Id`")]
    public virtual long Id { get; private set; }

    [Property("`Name`")]
    public virtual string Name { get; set; }

    [HasMany(Cascade = ManyRelationCascadeEnum.AllDeleteOrphan, Inverse = true, Lazy = true)]
    public virtual IList<Applicant> Applicants { get; set; }

    public File() {
        this.Applicants = new List<Applicant>();
    }
}

Applicant

[ActiveRecord("`Applicant`", Lazy = true)]
public class Applicant : TestProDb<Applicant> {

    [PrimaryKey("`Id`")]
    public virtual long Id { get; private set; }

    [Property("`Surname`")]
    public virtual string Surname { get; set; }

    [BelongsTo(Column = "IdFile", Lazy = FetchWhen.OnInvoke)]
    public virtual File File { get; set; }
}

Now I want to select Files based on some Applicant criterias. The result Files should contain eagerly loaded Applicants:

using (new SessionScope()) {
    DetachedCriteria fileQuery = DetachedCriteria.For<File>();
    fileQuery.SetResultTransformer(new DistinctRootEntityResultTransformer());
    fileQuery.SetFetchMode("Applicants", NHibernate.FetchMode.Eager);
    fileQuery.CreateCriteria("Applicants").Add(Expression.Like("Surname", "a", MatchMode.Anywhere));

    IList<File> files = File.FindAll(fileQuery);
    foreach (File file in files) {
        foreach (Applicant applicant in file.Applicants) {
            Console.WriteLine(applicant.Surname);
        }
    }
}

From NHProof - first query when I perform FindAll:

SELECT this_.[Id]            as Id1_0_1_,
   this_.[Name]          as Name2_0_1_,
   applicant1_.[Id]      as Id1_1_0_,
   applicant1_.[Surname] as Surname2_1_0_,
   applicant1_.IdFile    as IdFile1_0_
FROM   [File] this_
   inner join [Applicant] applicant1_
     on this_.[Id] = applicant1_.IdFile
WHERE  applicant1_.[Surname] like '%a%' /* @p0 */

From NHProof - second query in loop Console.WriteLine(applicant.Surname):

SELECT applicants0_.IdFile    as IdFile1_,
   applicants0_.[Id]      as Id1_1_,
   applicants0_.[Id]      as Id1_1_0_,
   applicants0_.[Surname] as Surname2_1_0_,
   applicants0_.IdFile    as IdFile1_0_
FROM   [Applicant] applicants0_
WHERE  applicants0_.IdFile = 1 /* @p0 */

Why do I get an additional roundtrip to the database for each Applicant loop (second query example)? There should only be one DB query in total because of FetchMode.Eager. I'm totally confused about this. I even tried to remove the virtual keyword and set all lazy values to false. Still the same. Is this a bug?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(1

深海少女心 2024-11-15 13:02:26

您收到额外的请求,因为 NHibernate 急切加载关联需要外连接,但查询中有内连接。要解决此问题,您需要指定:

JoinType.LeftOuterJoin

我遇到了类似的问题。

编辑

NHibernate 需要左连接的原因如下,请考虑以下代码:

DetachedCriteria fileQuery = DetachedCriteria.For<File>();
fileQuery.SetFetchMode("Applicants", NHibernate.FetchMode.Eager);

如果 NHibernate 在这里进行内连接,则没有申请人的文件将不会出现在查询结果中。这可能不是您所期望的。

但是,当您对申请人姓名创建限制时,您肯定不希望申请人的文件为空。这允许 NHibernate 稍微优化查询,但禁用延迟加载。

You are getting additional request because for NHibernate to eager load associations requires outer join, but you have inner join in query. To fix this you need to specify:

JoinType.LeftOuterJoin

I've had similar issue.

EDIT

The reason why NHibernate requires left join is the following, consider the following code:

DetachedCriteria fileQuery = DetachedCriteria.For<File>();
fileQuery.SetFetchMode("Applicants", NHibernate.FetchMode.Eager);

If NHibernate would made inner join here then Files that doesn't have Applicants won't be present in query result. Thats probably not what you would expect.

But when you create a restriction on Applicants name then you definitely don't want files that have applicants empty. That allows NHibernate to optimize query a bit, but disables lazy loading.

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