Performance NHibernate为多个父对象批量加载子对象

Performance NHibernate为多个父对象批量加载子对象,performance,nhibernate,fluent-nhibernate,bulk-load,Performance,Nhibernate,Fluent Nhibernate,Bulk Load,假设我们有一个类别表和产品表。以及每种产品的参考类别。因此,每个类别都有许多产品。 我想在没有产品的情况下加载许多类别(以减少数据库访问时间),然后检查我们实际需要的类别,并定义一个少得多的类别子集。 在此之后,我需要加载所选类别的所有产品,并使用单个DB查询将它们附加到类别。 我可以单独加载产品,但在这种情况下,它们不会附加到类别。这种方法,解决方案是在NHiberante中本地构建的。它被称为: NHibernate可以有效地利用批取,也就是说,如果访问一个代理(或集合),NHibernat

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

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

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

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

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

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


...
小结:有一个优化映射设置:
batch size=“25”

我们可以在类级别上使用它(稍后用于
多对一
关系)或在集合上使用它(直接在
一对多
realtion上)

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


检查,还有更多的链接…

这可以通过HQL和futures实现

鉴于实体和地图如下所示

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();
    }
}

相同(使用未来)适用于
查询版本
标准

这里的问题是,我只需要加载选定类别的产品,而不需要加载所有已加载的产品。我真的不会尝试解决,也不会比本机内置功能更智能。只要尝试,用我的(嗯,NHibernate)加载所有类别的所有产品即可方法。检查性能。然后通过查询选择几个类别,然后再次加载所有产品。我相信,您会感到惊讶,几乎没有什么不同。使用内置功能很难替代刚选择的加载所带来的性能提升。我每天都在使用批处理大小,我确信我可以只查询一个根,如果需要,所有关系都会被加载。工作得非常好…这实际上是我们现在处理它的方式。但它仍然有一个问题-正在提取(并可能重建)选定的类别这是第二次。但这只需要执行2次SQL,1.加载所有类别以进行筛选2.为筛选类别获取所有类别+产品的查询。因此,即使您设法将已加载的产品附加到已加载的类别,这有什么区别?
<class name="Person">
    <set name="Cats" batch-size="3">
        ...
    </set>
</class>
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();
    }
}
var categories = session.CreateQuery("from Category c join fetch c.Products where c.Id in (1,2)")
                    .Future<Category>().Distinct().ToList();
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);