流利的NHibernate N + 1问题与复杂的对象 [英] Fluent NHibernate N+1 issue with complex objects
问题描述
正如你将看到的,我的尝试涉及指定不延迟加载其他对象,但它似乎并没有这样做。
这是查询:
public IQueryable< Report> ReadAll(DateTime since)
{
return m_session.QueryOver< Report>()
.JoinQueryOver(r => r.Mail)
。其中(m => m .Received> = since)
.List()
.AsQueryable();
非常感谢您的回应!
简化的对象图形$ b
public class Report:EntityBase
{
public virtual Product Product {get;组; }
公共虚拟StackTrace StackTrace {get;组; }
public virtual Mail Mail {get;组; }
公共虚拟IList< ClientUser> ReadBy {get;组; }
$ / code $ / pre
$ -
public class Product:EntityBase
{
public virtual string Name {get;组; }
public virtual Version Version {get;组; }
公共虚拟IList<报告>报告{get;组; }
公共虚拟IList< StackTrace> StackTraces {get;组; }
$ / code $ / pre
$ -
public class StackTrace:EntityBase
{
public virtual IList< StackTraceEntry>条目{get;组; }
公共虚拟IList<报告>报告{get;组; }
public virtual Product Product {get;组;
$ b 映射示例:
public class ReportMap:ClassMap< Report>
{
public ReportMap()
{
Table(Report);
引用(x => x.User)
.Column(EndUserId)
.Not.LazyLoad();
引用(x => x.Product)
.Column(ProductId)
.Not.LazyLoad();
引用(x => x.StackTrace)
.Column(StackTraceId)
.Not.LazyLoad();
HasManyToMany(x => x.ReadBy)
.Cascade.SaveUpdate()
.Table(ClientUserRead)
.ParentKeyColumn(ReportId)
.ChildKeyColumn(ClientUserId)
.Not.LazyLoad()。BatchSize(200);
public class StackTraceMap:ClassMap< StackTrace>
{
public StackTraceMap()
{
Table(StackTrace);
引用(x => x.Product)
.Column(ProductId);
HasMany(x => x.Entries)
.KeyColumn(StackTraceId)
.Not.LazyLoad()
.Cascade
。所有()BATCHSIZE(500);
HasMany(x => x.Reports)
.KeyColumn(StackTraceId)
.Inverse()。BatchSize(100);
$ / code $ / pre
解决方案要走的路线是使用批量抓取。阅读更多关于它在这里:
如何加载关联NHibernate中没有重复?
在每个实体映射上应用 BatchSize
多对一
关系 - 避免1 + N)
public ReportMap()
{
Table(...)
BatchSize(25);
...
在每个集合上解决一对多
1 + N)
HasMany(x => x.Reports)
.KeyColumn(StackTraceId)
.BatchSize(25)
...
I'm having a problem with NHibernate querying the database way too many times. I just realized it likely relates to the n+1 problem but I can't figure out how to change my mappings to solve the problem.
As you will see, my attempts involve specifying not to lazy load other objects, but it doesn't seem to do the trick.
This is the query:
public IQueryable<Report> ReadAll(DateTime since)
{
return m_session.QueryOver<Report>()
.JoinQueryOver(r => r.Mail)
.Where(m => m.Received >= since)
.List()
.AsQueryable();
}
Thanks in advance for any response! If you need any more information about my objects or mappings, please let me know.
Simplified objects graph (some omitted):
public class Report : EntityBase
{
public virtual Product Product { get; set; }
public virtual StackTrace StackTrace { get; set; }
public virtual Mail Mail { get; set; }
public virtual IList<ClientUser> ReadBy { get; set; }
}
-
public class Product : EntityBase
{
public virtual string Name { get; set; }
public virtual Version Version { get; set; }
public virtual IList<Report> Reports { get; set; }
public virtual IList<StackTrace> StackTraces { get; set; }
}
-
public class StackTrace : EntityBase
{
public virtual IList<StackTraceEntry> Entries { get; set; }
public virtual IList<Report> Reports { get; set; }
public virtual Product Product { get; set; }
}
Mapping examples:
public class ReportMap : ClassMap<Report>
{
public ReportMap()
{
Table("Report");
References(x => x.User)
.Column("EndUserId")
.Not.LazyLoad();
References(x => x.Product)
.Column("ProductId")
.Not.LazyLoad();
References(x => x.StackTrace)
.Column("StackTraceId")
.Not.LazyLoad();
HasManyToMany(x => x.ReadBy)
.Cascade.SaveUpdate()
.Table("ClientUserRead")
.ParentKeyColumn("ReportId")
.ChildKeyColumn("ClientUserId")
.Not.LazyLoad().BatchSize(200);
}
}
-
public class StackTraceMap : ClassMap<StackTrace>
{
public StackTraceMap()
{
Table("StackTrace");
References(x => x.Product)
.Column("ProductId");
HasMany(x => x.Entries)
.KeyColumn("StackTraceId")
.Not.LazyLoad()
.Cascade
.All().BatchSize(500);
HasMany(x => x.Reports)
.KeyColumn("StackTraceId")
.Inverse().BatchSize(100);
}
}
解决方案 The way to go is to use batch fetching. Read more about it here:
How to Eager Load Associations without duplication in NHibernate?
On every entity mapping apply BatchSize
(for many-to-one
relation - avoiding 1 + N)
public ReportMap()
{
Table(...)
BatchSize(25);
...
And on every collection (solves issue with one-to-many
1 + N)
HasMany(x => x.Reports)
.KeyColumn("StackTraceId")
.BatchSize(25)
...
这篇关于流利的NHibernate N + 1问题与复杂的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!