流利的NHibernate N + 1问题与复杂的对象 [英] Fluent NHibernate N+1 issue with complex objects

查看:117
本文介绍了流利的NHibernate N + 1问题与复杂的对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个NHibernate查询数据库的方式太多的问题。我只是意识到它可能涉及到n + 1的问题,但我不知道如何改变我的映射来解决问题。



正如你将看到的,我的尝试涉及指定不延迟加载其他对象,但它似乎并没有这样做。



这是查询:

  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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆