NHibernate使用HasOne Mapping选择N + 1

时间:2016-02-07 03:33:26

标签: sql-server linq nhibernate fluent-nhibernate iqueryable

我有两个由以下实体建模的表:

public class Product : ModifiableEntity
{
    public virtual int ProductId { get; set; }

    public virtual string Description { get; set; }

    public virtual ProductStats Stats { get; set; }
}

public class ProductStats : ModifiableEntity
{
    public virtual int ProductStatId { get; set; }

    public virtual int? QtyAvail { get; set; }7

    public virtual Product Product { get; set; }
}

使用以下流畅的映射:

public class ProductMap : ModifiableEntityClassMap<Product>
{
    public ProductMap()
    {
        Table("Product");
        Id(x => x.ProductId).Column("ProductId").GeneratedBy.Identity();

        Map(x =>     x.Description).Column("Description").Nullable().Length(Int32.MaxValue);

        HasOne(x => x.Stats)
            .PropertyRef(x => x.Product)
            .Cascade.All();
    }
}


public class ProductStatsMap : ModifiableEntityClassMap<ProductStats>
{
    public ProductStatsMap()
    {
        Table("ProductStats");
        Id(x => x.ProductStatId).Column("ProductStatId").GeneratedBy.Identity();

        Map(x => x.QtyAvail).Column("QtyAvail").Nullable();

        References(x => x.Product).Column("ProductId")
                                  .Unique()
                                  .Cascade.All()
                                  .Not.Nullable();
    }
}

我的测试数据库中有7005个产品,产品和产品统计信息之间的内部联接是1比1并返回7005条记录,但是当我运行以下查询时,我在SQL事件探查器中看到了近30,0000个查询。

 var products = from p in _productRepository.Linq()
                select p;

我尝试过各种变体:

        HasOne(x => x.Stats)
            .Not.LazyLoad().Fetch.Join()
            .PropertyRef(x => x.Product)
            .Cascade.All();

除了在linq查询中指定fetch之外,无论我尝试什么,结果都是针对我的SQL服务器运行了数万个查询。

任何人都可以提供任何帮助,我们将不胜感激。

提前谢谢。

1 个答案:

答案 0 :(得分:0)

我认为这里的问题是您需要急切加载 ProductStats 。您可以通过两种方式实现这一目标:

  1. 在映射Stats属性时添加 .Not.LazyLoad(),如下所示:

    HasOne(x => x.Stats)
        .PropertyRef(x => x.Product)
        .Not.LazyLoad()
        .Cascade.All();
    
    1. 使用命名空间 NHibernate.Linq ,如下所示:

      session.Query<Product>().Fetch(p => p.Stats).ToFuture();
      

      这将使NHibernate仅在一次数据库往返中执行两个查询。第一个查询将获取产品,第二个查询将获取在第一个产品中获取的每个productStats。

    2. 第一种方法的唯一问题是它会影响您执行的每个查询。另一方面,只有在真正需要时才能使用第二种方法。

      尽管如此,仍有一些问题困扰着我:你真的需要&#34;产品&#34;属性中的属性?因为你可能在循环引用方面遇到一些问题。