NHibernate只急切地加载Dictionary<;地图>;在执行代码时

本文关键字:gt 地图 执行 代码 lt 加载 Dictionary NHibernate | 更新日期: 2023-09-27 18:27:34

我有一个Unit类,其DictionaryParts。映射看起来像这个

<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;

下面的代码让我很困惑。当我使用调试器逐步完成它时,UnitParts 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;
        }
    }
}

如有任何提示,不胜感激。

附言:我使用了[调试]标签,因为这似乎是这个场景中的关键。

NHibernate只急切地加载Dictionary<;地图>;在执行代码时

如何从数据库接收数据有两个不同的概念。在一对多(列表、词典)的情况下。

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的功能-一切都是懒惰的