NHibernate只急切地加载Dictionary<;地图>;在执行代码时
本文关键字:gt 地图 执行 代码 lt 加载 Dictionary NHibernate | 更新日期: 2023-09-27 18:27:34
我有一个Unit
类,其Dictionary
为Parts
。映射看起来像这个
<class name="Unit" table="Units">
<id name="Id">
<generator class="native"/>
</id>
<property name="CreationDate" />
<property name="MacAddress" />
<property name="OEMId" />
<property name="SerialNumber" />
<property name="QualityControlState" />
<map name="Parts" table="UnitParts" lazy="false">
<key column="UnitId"/>
<index column="TypeOfPart" type="integer"/>
<composite-element class="UnitPart">
<property name="PartInfo"/>
<property name="Remarks"/>
</composite-element>
</map>
当我Session.SaveOrUpdate(Unit)
一切顺利时:两个表都填充了正确的数据。并且该单元也可以使用Session.Get(typeof(Unit)
来检索(具有其所有的Parts
)。
问题:获取多个单元延迟加载Parts
Dictionary
用伪码改写的问题:LoadMethodOfPartsDictionary = (Stepping with Debugger) ? Eagerly : Lazy;
下面的代码让我很困惑。当我使用调试器逐步完成它时,Unit
的Parts
Dictionary
会被急切地加载。但当我运行到return Units
(而不是通过Units = crit.Future<Unit>().ToList<Unit>();
)时,NHibernate似乎想延迟加载,因为Parts
Dictionary
突然变成了NHibernate.Collection.Generic.PersistentGenericMap
。
/// <summary>
/// Retreives a list of units by a set of criteria.
/// </summary>
/// <returns>A list of units that fall within/match the criteria</returns>
public static List<Unit> GetUnits(List<KeyValuePair<Unit.SortableProperties, ListSortDirection>> SortColumnOrder, out uint NumberOfRecordsWithoutLimit, uint Start = 0, int End = -1, FilterUnits Filter = default(FilterUnits))
{
List<Unit> Units = default(List<Unit>);
NumberOfRecordsWithoutLimit = 0;
using (ISession Session = ORM.SessionFactory.OpenSession())
{
using (ITransaction Transaction = Session.BeginTransaction())
{
ICriteria crit = Session.CreateCriteria<Unit>();
//Limit result set, used for paging
if (End > 0)
{
crit.SetFirstResult((int)Start);
crit.SetMaxResults(End);
}
//TODO: Implement filter code here
//Add the sort order
foreach (KeyValuePair<Unit.SortableProperties, ListSortDirection> kvp in SortColumnOrder)
{
String PropertyName = "";
switch (kvp.Key)
{
case Unit.SortableProperties.PRODUCTIONDATE:
PropertyName = "CreationDate";
break;
default:
throw new NotImplementedException(kvp.Key.ToString() + " isn't implemented for sorting yet.");
}
crit.AddOrder(new Order(PropertyName, (kvp.Value == ListSortDirection.Ascending)));
}
if (End > 0)
{
//Count the total units available in database.
Units = crit.Future<Unit>().ToList<Unit>(); //This seems to lazy load the Units
IFutureValue<int> RowCount = Session.CreateCriteria<Unit>()
.SetProjection(Projections.Count(Projections.Id()))
.FutureValue<int>();
NumberOfRecordsWithoutLimit = (uint)RowCount.Value;
}
else
{
Units = (List<Unit>)crit.List<Unit>();
NumberOfRecordsWithoutLimit = (uint)Units.Count;
}
Transaction.Commit();
Session.Close();
return Units;
}
}
}
如有任何提示,不胜感激。
附言:我使用了[调试]标签,因为这似乎是这个场景中的关键。
如何从数据库接收数据有两个不同的概念。在一对多(列表、词典)的情况下。
1) 我们可以调用NHibernate通过ID或参考(类似情况)获取数据
session.Get<Unit>(1);
在这种情况下,NHibernates注入所有标记为lazy的属性而非。所以,在您的情况下,这将导致急切地加载零件,以及。
类似的是一个OtherObject
的参考性质:public virtual Unit Unit { get; set; }
var otherObject = ... // get from session
var unit = otherObject.Unit; // the full Unit with all `Lazy="false"` properties is loaded
2) 但我们也可以使用Criteria
(如您的情况)。然而,这是一种不同的方法。在这种情况下,我们明确表示,我们只想使用Unit
Units = crit.Future<Unit>().ToList<Unit>();
这有很多优点:
- 我们只能在
Unit
表上进行有效的分页 - 只有单元被加载(可能零件不会被使用)
- 如果使用零件,则会延迟加载
但如果真的需要(考虑到间接寻呼等副作用),我们也可以在一个选项中加载部件:
Units = crit
.SetFetchMode("Parts", FetchMode.Eager)
.Future<Unit>()
.ToList<Unit>();
现在所有人都同时被填满了。
3) 我会投票支持的方法(我使用100%)是让集合变得懒惰,并分配batch-size
19.1.5。使用批量提取
扩展
向您展示如何更改映射:
<map name="Parts" table="UnitParts" lazy="true" batch-size="25">
从那一刻起,你的尤蒂尔就变得轻盈了。没有装载零件,直到真正需要。如果会话在整个请求过程中打开,一旦接触到部件,它们将被加载到一个SELECT中(如果Utils的页面大小不大于25)
这种方法非常有效,因为它使用了ORM的功能-一切都是懒惰的