为什么NHibernate不抓取我的数据
我正在使用Nhibernate作为我的ORM 我有一个类“Control”,它与ControlDetail有一对多的关系(即控件有许多controlDetails) 在控件xml配置中,它具有以下内容为什么NHibernate不抓取我的数据,nhibernate,eager-loading,Nhibernate,Eager Loading,我正在使用Nhibernate作为我的ORM 我有一个类“Control”,它与ControlDetail有一对多的关系(即控件有许多controlDetails) 在控件xml配置中,它具有以下内容 <bag name="ControlDetails" lazy="true" access="property" order-by="SortOrder asc" cascade="all-delete-orphan" table="ControlDetail"> <
<bag name="ControlDetails" lazy="true" access="property" order-by="SortOrder asc" cascade="all-delete-orphan"
table="ControlDetail">
<key column="ControlID"/>
<one-to-many class="ControlDetail"/>
</bag>
因此,我相信除非另有说明,否则它将延迟加载控件的控件详细信息
我正在运行NHProf,试图修复我们遇到的一些性能问题,它已经确定了这些类的一个Select N+1问题
我们正在使用一个存储库DA层,我试图看看是否可以添加一种方式,以便在需要时急切地获取数据,并提出了这个方法
public T GetById<T>(Int32 id, List<string> fetch) where T : BaseObject
{
T retObj = null;
ISession session = EnsureCurrentSession();
{
ICriteria criteria = session.CreateCriteria(typeof (T));
criteria.SetCacheable(true);
criteria.Add(Expression.Eq("Id", id));
foreach(var toFetch in fetch)
{
criteria.SetFetchMode(toFetch, FetchMode.Eager);
}
retObj = criteria.List<T>().FirstOrDefault();
}
return retObj;
}
public T GetById(Int32 id,List fetch),其中T:BaseObject
{
T retObj=null;
ISession session=ensureRecurrentSession();
{
ICriteria-criteria=session.CreateCriteria(typeof(T));
条件。可设置缓存(true);
添加(表达式.Eq(“Id”,Id));
foreach(提取中的变量toFetch)
{
SetFetchMode(toFetch,FetchMode.Eager);
}
retObj=criteria.List().FirstOrDefault();
}
返回retObj;
}
*注意:我不喜欢如何设置存储库,但它是在我进入项目之前完成的,所以我们现在必须坚持这种模式
我这样称呼这个方法
public Control GetByIDWithDetail(int controlID)
{
return DataRepository.Instance.GetById<Control>(controlID, new List<string>() {"ControlDetail"});
}
公共控件GetById WithDetail(int-controlID)
{
返回DataRepository.Instance.GetById(controlID,new List(){“ControlDetail”});
}
当我调试GetByID方法并查看retObj时,我可以看到ControlDetails列表已经填充(尽管奇怪的是,我还注意到,如果没有setfetchmode设置,列表已经填充)
即使使用此修复程序,NHProf也会通过以下行识别Select N+1问题
List<ControlDetail> details = control.ControlDetails.ToList();
List details=control.ControlDetails.ToList();
我到底遗漏了什么?我如何停止这个N+1,但仍然在controlDetails列表上迭代
编辑:xml配置看起来是这样的(稍微编辑以使其更小)
还有这个
一个选项,您可以减少选择n+1问题,保持延迟加载,并忘记快速加载 您只需向XML添加一个简单的属性
batch size
<bag name="ControlDetails" batch-size="25" ..>
我还注意到,您的映射中有
lazy=“true”
,您是否尝试更改为false?即时抓取和即时加载之间有很大区别。取数的意思是:放入同一个查询。它有几个副作用,可能会破坏它。急切加载意味着强制NH立即加载它,而不是等到第一次访问它。它仍然使用其他查询加载,这导致了N+1问题
NH可能不急于获取,因为该属性名为ControlDetails
,但您将ControlDetail
作为参数传递
另一方面,这不是避免N+1问题的好方法。改为使用批量大小。它对应用程序完全透明,并按给定的因子减少查询量(值从5到50是有意义的,如果不知道使用什么,请使用10)。最有可能的是“控件”来自一级缓存,但关系是延迟加载的,因为关系未设置为与父级缓存。抓取NHProf并查看缓存命中与查询。NHProf在查询缓存命中/未命中/放置计数中显示为0,在二级缓存命中/未命中/放置计数中显示为0,我将如何解决此问题?控件和控件详细信息的命中率都是0吗?或者只是ControlDetail?哦,实际上,我认为它也不会缓存,因为您的映射没有设置为缓存。Hmmm@mathieu:没错。并尝试在同一查询中获取多个集合。有一个DistinctCollectionItemTransformer,但没有“DistinctCollectionItemTransformer”。一切都会成倍增长。我还遇到了一些奇怪的问题,查询中的列太多了。我真的停止使用它了。
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="DomainObjects" assembly="DomainObjects">
<class name="ControlDetail" lazy="false" table="ControlDetail" select-before-update="true" optimistic-lock="version">
<id name="Id" type="int" column="ControlDetailID" access="property">
<generator class="native" />
</id>
<version name="Version" column="Version" />
<property name="Description" column="Description" access="property" not-null="true" />
<property name="Title" column="Title" access="property" />
<many-to-one name="Control" lazy="false" class="Control" column="ControlID" access="property"/>
</class>
</hibernate-mapping>
<bag name="ControlDetails" batch-size="25" ..>