我有这个设置:父,有一个儿童的集合.
class Parent {
IList<Child> Childs { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
HQL:
("来自父母").期货();
("来自孩子").未来();
foreach(Parent p in result) {
foreach(Child c in p.Childs) {
}
}
Run Code Online (Sandbox Code Playgroud)
这给出了经典的N + 1问题.两个SQL语句在1次往返中发送到服务器,因此所有数据都存在于一级缓存中,那么为什么NH仍然存在每个子进程的SQL.
版本3.1.0.400
执行将来的查询时,将所有父对象和子对象都拉入第一级缓存.Parent对象包含一个需要填充的惰性集合.要填充集合,NHibernate必须查询数据库.(我们将在一秒钟内了解原因.)查询返回Child对象,这些子对象已经在L1缓存中.因此,这些对象用于填充集合.
现在为什么NHibernate必须查询数据库来填充Childs集合?您可以在集合上使用"where"子句过滤掉IsDeleted == true的Child对象.您可以在EventListener中使用过滤掉某些Child对象的代码.基本上可以发生很多事情,NHibernate不能对Parent和Child对象之间的关系做出任何假设.
您可以通过在HQL或映射中指定提取策略来为其提供足够的信息.在HQL中,您可以编写:
var parents = session.CreateQuery("from Parent p join fetch p.Childs").Future<Parent>();
Run Code Online (Sandbox Code Playgroud)
当您使用父级获取子项时,使用future的Child对象查询将是完全可选的.由于连接提取,您将获得重复的父对象,尽管它们将是同一个对象.(您正在数据库中进行内部联接,并为每个子行返回父行的一个副本.)您可以通过迭代parent.Distinct()来摆脱这些行.
如果您总是想要使用相应的Parent获取Child对象,则还可以在Parent映射中使用fetch ="join".
<bag name="Children" cascade="all-delete-orphan" fetch="join">
<key column="ParentId"/>
<one-to-many class="Child"/>
</bag>
Run Code Online (Sandbox Code Playgroud)
如果这些选项都不适用于您的方案,则可以在集合映射上指定批量大小.当你点击parent.Childs时,你仍然会执行数据库查询,但NHibernate会急切地初始化任何其他集合代理.
<bag name="Children" cascade="all-delete-orphan" batch-size="10">
<key column="ParentId"/>
<one-to-many class="Child"/>
</bag>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
959 次 |
| 最近记录: |