NHibernate 为多个父级批量加载子对象
NHibernate bulk loading child objects for multiple parents
假设我们有类别 table 和产品 table。每个产品引用类别。所以每个类别都有很多产品。
我想加载许多没有产品的类别(以减少数据库访问时间),然后检查我们实际需要的类别并定义一个更少的类别子集。
在此之后,我需要加载选定类别的所有产品,并使用单个数据库查询将它们附加到类别。
我可以单独加载产品,但在那种情况下它们不会附加到类别。
这种方法、解决方案是在 NHiberante 中原生构建的。它被称为:
19.1.5. Using batch fetching
NHibernate can make efficient use of batch fetching, that is, NHibernate can load several uninitialized proxies if one proxy is accessed (or collections. Batch fetching is an optimization of the lazy select fetching strategy. There are two ways you can tune batch fetching: on the class and the collection level.
Batch fetching for classes/entities is easier to understand. Imagine you have the following situation at runtime: You have 25 Cat instances loaded in an ISession, each Cat has a reference to its Owner, a Person. The Person class is mapped with a proxy, lazy="true". If you now iterate through all cats and call cat.Owner on each, NHibernate will by default execute 25 SELECT statements, to retrieve the proxied owners. You can tune this behavior by specifying a batch-size in the mapping of Person:
<class name="Person" batch-size="10">...</class>
NHibernate will now execute only three queries, the pattern is 10, 10, 5.
You may also enable batch fetching of collections. For example, if each Person has a lazy collection of Cats, and 10 persons are currently loaded in the ISesssion, iterating through all persons will generate 10 SELECTs, one for every call to person.Cats. If you enable batch fetching for the Cats collection in the mapping of Person, NHibernate can pre-fetch collections:
<class name="Person">
<set name="Cats" batch-size="3">
...
</set>
</class>
摘要:有一个优化映射设置:batch-size="25"
。
我们可以在 class 级别 (稍后用于 many-to-one
关系) 或集合 (直接在 one-to-many
关系)
这将导致很少有 SELECT 语句来加载复杂的对象图。最重要的好处是,我们可以在查询根实体时使用分页(Take()
、Skip()
)(没有多行)
检查 also this,还有更多链接...
这可以通过 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);
同样(使用 future)适用于 queryover
或 criteria
假设我们有类别 table 和产品 table。每个产品引用类别。所以每个类别都有很多产品。 我想加载许多没有产品的类别(以减少数据库访问时间),然后检查我们实际需要的类别并定义一个更少的类别子集。 在此之后,我需要加载选定类别的所有产品,并使用单个数据库查询将它们附加到类别。 我可以单独加载产品,但在那种情况下它们不会附加到类别。
这种方法、解决方案是在 NHiberante 中原生构建的。它被称为:
19.1.5. Using batch fetching
NHibernate can make efficient use of batch fetching, that is, NHibernate can load several uninitialized proxies if one proxy is accessed (or collections. Batch fetching is an optimization of the lazy select fetching strategy. There are two ways you can tune batch fetching: on the class and the collection level.
Batch fetching for classes/entities is easier to understand. Imagine you have the following situation at runtime: You have 25 Cat instances loaded in an ISession, each Cat has a reference to its Owner, a Person. The Person class is mapped with a proxy, lazy="true". If you now iterate through all cats and call cat.Owner on each, NHibernate will by default execute 25 SELECT statements, to retrieve the proxied owners. You can tune this behavior by specifying a batch-size in the mapping of Person:
<class name="Person" batch-size="10">...</class>
NHibernate will now execute only three queries, the pattern is 10, 10, 5.
You may also enable batch fetching of collections. For example, if each Person has a lazy collection of Cats, and 10 persons are currently loaded in the ISesssion, iterating through all persons will generate 10 SELECTs, one for every call to person.Cats. If you enable batch fetching for the Cats collection in the mapping of Person, NHibernate can pre-fetch collections:
<class name="Person">
<set name="Cats" batch-size="3">
...
</set>
</class>
摘要:有一个优化映射设置:batch-size="25"
。
我们可以在 class 级别 (稍后用于 many-to-one
关系) 或集合 (直接在 one-to-many
关系)
这将导致很少有 SELECT 语句来加载复杂的对象图。最重要的好处是,我们可以在查询根实体时使用分页(Take()
、Skip()
)(没有多行)
检查 also this,还有更多链接...
这可以通过 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);
同样(使用 future)适用于 queryover
或 criteria