NHibernate批量加载多个父项的子对象

时间:2015-04-06 11:46:52

标签: performance nhibernate fluent-nhibernate bulk-load

假设我们有一个Category表和Product表。每个产品都引用了Category。所以每个类别都有很多产品。 我想加载许多没有产品的类别(减少数据库访问时间),然后检查我们实际需要的类别,并定义更少的类别子集。 在此之后,我需要加载所选类别的所有产品,并使用单个数据库查询将它们附加到类别。 我可以单独加载产品,但在这种情况下,它们不会附加到类别。

2 个答案:

答案 0 :(得分:1)

这种解决方案本身就是在NHiberante中构建的。它被称为:

19.1.5. Using batch fetching

  

NHibernate可以有效地使用批量提取,也就是说,如果访问一个代理(或集合),NHibernate可以加载几个未初始化的代理。批量提取是懒惰选择提取策略的优化。有两种方法可以调整批处理获取:在类和集合级别上。

     

更容易理解批量提取类/实体。想象一下,您在运行时遇到以下情况:您在一个ISession中加载了25个Cat实例,每个Cat都有一个对其所有者的引用,一个Person。 Person类使用代理映射,lazy =“true”。如果您现在遍历所有猫并在每个猫上调用cat.Owner,NHibernate将默认执行25个SELECT语句,以检索代理所有者。您可以通过在Person:

的映射中指定批量大小来调整此行为
<class name="Person" batch-size="10">...</class>
  

NHibernate现在只执行三个查询,模式为10,10,5。

     

您还可以启用批量提取集合。例如,如果每个Person都有一个懒惰的Cats集合,并且当前在ISesssion中加载了10个人,则遍历所有人将生成10个SELECT,每个人调用一个SELECT.Cats。如果在Person的映射中为Cats集合启用批量获取,NHibernate可以预取集合:

<class name="Person">
    <set name="Cats" batch-size="3">
        ...
    </set>
</class>

摘要:有一个优化映射设置: batch-size="25"

我们可以在课堂级(稍后用于many-to-one关系)或集合(直接在one-to-many实现中)

这将导致很少的SELECT语句加载复杂的对象图。最重要的好处是,当我们查询根实体(没有多行)时,我们可以使用分页(Take()Skip()

检查also this,甚至更多链接......

答案 1 :(得分:1)

这可以通过HQL和期货来实现

给出实体和地图如下,

public class Category
{
    private IList<Product> _products; 

    public Category()
    {
        _products = new List<Product>();
    }

    public virtual int Id { get; set; }
    public virtual string CategoryName { get; set; }
    public virtual IList<Product> Products
    {
        get { return _products; }
        set { _products = value; }
    }
}

public class CategoriesClassMap : ClassMap<Category>
{
    public CategoriesClassMap()
    {
        Table("Categories");
        Id(x => x.Id).GeneratedBy.Native();
        Map(x => x.CategoryName);
        HasMany<Product>(c => c.Products).LazyLoad();
    }
}

public class Product
{
    public virtual int Id { get; set; }
    public virtual string ProductName { get; set; }
    public virtual Category Category { get; set; }
}

public class ProductSClassMap : ClassMap<Product>
{
    public ProductSClassMap()
    {
        Table("Products");
        Id(x => x.Id).GeneratedBy.Native();
        Map(x => x.ProductName);
        References<Category>(x => x.Category).Not.Nullable();
    }
}

使用以下HQL,它将在一个查询中加载所有类别和产品,

var categories = session.CreateQuery("from Category c join fetch c.Products where c.Id in (1,2)")
                    .Future<Category>().Distinct().ToList();

它只获取与类别id 1和2相关的数据。生成的SQL看起来像

select category0_.Id as Id1_0_, products1_.Id as Id3_1_, category0_.CategoryName as Category2_1_0_, products1_.ProductName as ProductN2_3_1_, products1_.Category_id as Category3_3_1_, products1_.Category_id as Category3_0__, products1_.Id as Id0__ from Categories category0_ inner join Products products1_ on category0_.Id=products1_.Category_id where category0_.Id in (1 , 2);

同样(使用未来)适用于queryovercriteria