[英]NHibernate only eagerly loads Dictionary <map> when stepping through code
I have a class Unit
with a Dictionary
of Parts
. 我有一个带
Parts
Dictionary
的班级Unit
。 The mapping looks like this 映射看起来像这样
<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>
When I Session.SaveOrUpdate(Unit)
all goes well: the two tables are filled with the right data. 当我
Session.SaveOrUpdate(Unit)
一切顺利时:两个表中填充正确的数据。 And the unit is retreivable (with all its Parts
) using Session.Get(typeof(Unit)
as well. 并且该单元也可以使用
Session.Get(typeof(Unit)
)进行Session.Get(typeof(Unit)
及其所有Parts
)。
The problem: Obtaining multiple units lazy loads the Parts
Dictionary
. 问题:延迟获取多个单元会加载
Parts
Dictionary
。
The problem rephrased in pseudo code: LoadMethodOfPartsDictionary = (Stepping with Debugger) ? Eagerly : Lazy;
该问题用伪代码改写:
LoadMethodOfPartsDictionary = (Stepping with Debugger) ? Eagerly : Lazy;
LoadMethodOfPartsDictionary = (Stepping with Debugger) ? Eagerly : Lazy;
The following code baffles me. 以下代码使我感到困惑。 When I step through it using the debugger the
Parts
Dictionary
of a Unit
is eagerly loaded. 当我使用调试器逐步调试时,会急切加载
Unit
的Parts
Dictionary
。 But when I run to return Units
(not stepping through Units = crit.Future<Unit>().ToList<Unit>();
) its seems NHibernate wants to lazy load as the Parts
Dictionary
suddenly is NHibernate.Collection.Generic.PersistentGenericMap
. 但是当我运行
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;
}
}
}
Any hints are appreciated. 任何提示表示赞赏。
PS I used the [Debugging] tag as this seems to be key in this scenario. PS我使用[Debugging]标签,因为在这种情况下这似乎很关键。
There are two different concepts how to recieve the data from the DB. 如何从数据库中接收数据有两种不同的概念。 In case of one-to-many (lists, dictionaries).
如果是一对多(列表,字典)。
1) We can call NHibernate to get data by ID or reference (similar cases) 1)我们可以调用NHibernate通过ID或引用获取数据(类似情况)
session.Get<Unit>(1);
In this case NHibernates injects all the properties not marked as lazy . 在这种情况下,NHibernates注入所有未标记为lazy的属性。 So in your case, this will cause to eagerly load of the Parts as well.
因此,在您的情况下,这也将导致零件的急切加载。
the similar is the reference property: public virtual Unit Unit { get; set; }
参考属性类似:
public virtual Unit Unit { get; set; }
public virtual Unit Unit { get; set; }
public virtual Unit Unit { get; set; }
of ane OtherObject
public virtual Unit Unit { get; set; }
ANE的OtherObject
var otherObject = ... // get from session
var unit = otherObject.Unit; // the full Unit with all `Lazy="false"` properties is loaded
2) But we can also use the Criteria
(As in your case). 2)但是我们也可以使用
Criteria
(根据您的情况)。 However, this is different approach. 但是,这是不同的方法。 In this case, we are explicitly saying that we want only work with
Unit
在这种情况下,我们明确地说我们只希望与
Unit
Units = crit.Future<Unit>().ToList<Unit>();
This has many advantages: 这具有许多优点:
Unit
table Unit
表上进行有效的分页 But if really needed (regardles of side effects like inocrrect paging) we can also load the Parts in one select: 但是,如果确实需要(不正确的分页之类的副作用),我们也可以选择加载部件:
Units = crit
.SetFetchMode("Parts", FetchMode.Eager)
.Future<Unit>()
.ToList<Unit>();
Now is all populated at once. 现在全部填充一次。
3) The approach I would vote for (I am using 100%) is to let collection to be lazy, and assign the batch-size
19.1.5. 3)我要投票的方法(我正在使用100%)是让collection变得懒惰,并分配19.1.5的
batch-size
。 Using batch fetching 使用批量提取
EXTENDED EXTENDED
To show you how to change the mapping: 向您展示如何更改映射:
<map name="Parts" table="UnitParts" lazy="true" batch-size="25">
From that moment, your Util is lightweight. 从那时起,您的Util变得轻巧。 No Parts loaded, until really needed.
直到真正需要时才加载零件。 If the session is opened during the whole request, once the Parts are touched, they will be loaded in one SELECT (if the page size of Utils is not larger then 25)
如果在整个请求期间都打开了会话,则在触摸部件后,它们将被加载到一个SELECT中(如果Utils的页面大小不大于25)
This approach is very efficient, becuase it uses the power of ORM - everything is lazy 这种方法非常有效,因为它使用了ORM的功能-一切都很懒惰
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.