简体   繁体   English

NHibernate只积极加载Dictionary <map> 单步执行代码时

[英]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. 当我使用调试器逐步调试时,会急切加载UnitParts 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: 这具有许多优点:

  • we can do efficient paging only on the Unit table 我们只能在Unit表上进行有效的分页
  • only the Unit is loaded (maybe the Parts won't be used) 仅加载单元(也许不使用零件)
  • if Parts are used, they will be lazily loaded 如果使用零件,它们将被延迟加载

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.5batch-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.

相关问题 C# 仅在单步执行代码时出现调试错误 - C# Debugging Error Only When Stepping Through Code Jtable仅在逐步调试器时显示 - Jtable only displays when stepping through debugger 异步等待执行顺序-代码仅在逐步执行/调试时才有效 - async await execution order - code only actually works when stepping through/debugging 返回私有变量后的StackOverflowException,仅在单步执行代码时 - StackOverflowException after returning private variable, only while stepping through code LoadLibrary失败,代码为126,除非逐步执行代码 - LoadLibrary failing with code 126 except when stepping through the code 我单步执行程序时只会得到Stackoverflow异常 - I Only get a Stackoverflow exception when stepping through program VS2005:单步执行C#代码时,是否可以跳过代码部分? - VS2005: when stepping through C# code, is there way to skip through sections of code? 单步执行到单步执行时功能会有所不同 - Function behaves differently when stepping through to when stepping over 更新集合时出现奇怪的DB上下文行为(在调试器中逐步执行代码时有效) - Strange DB-context behaviour when updating collection (Works when stepping through the code in debugger) 在单元测试中单步调试和调试代码 - Stepping through and debugging code in Unit tests
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM