【问题标题】:ActiveRecord (NHibernate) Eager Loading Bug?ActiveRecord (NHibernate) 急于加载错误?
【发布时间】:2011-08-27 15:54:53
【问题描述】:

我有两个类: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; }
}

现在我想根据一些申请人标准来选择文件。结果 Files 应包含急切加载的 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);
        }
    }
}

来自 NHProof - 我执行 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,总共应该只有一个 DB 查询。我对此完全感到困惑。我什至尝试删除 virtual 关键字并将所有惰性值设置为 false。还是一样。这是一个错误吗?

【问题讨论】:

    标签: .net sql nhibernate castle-activerecord


    【解决方案1】:

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

    JoinType.LeftOuterJoin
    

    I've had similar issue.

    编辑

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

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

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

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

    【讨论】:

    • Sly,非常感谢,它现在可以工作了 :) 我仍然不明白为什么它使用 LeftOuterJoin 的别名。仅仅因为限制?
    • 您的解决方案效果很好,我最终将它与 Future() 结合使用,因为我必须一次加载多个子集合。谢谢!
    猜你喜欢
    • 2011-12-07
    • 2017-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-23
    • 1970-01-01
    相关资源
    最近更新 更多