ActiveRecord (NHibernate) 急切加载错误?
我有两个类:File、Applicant,我正在使用 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您收到额外的请求,因为 NHibernate 急切加载关联需要外连接,但查询中有内连接。要解决此问题,您需要指定:
我遇到了类似的问题。
编辑
NHibernate 需要左连接的原因如下,请考虑以下代码:
如果 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:
I've had similar issue.
EDIT
The reason why NHibernate requires left join is the following, consider the following code:
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.