1

のクラスUnitDictionaryあり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)、2 つのテーブルに適切なデータが入力されます。また、ユニットは (すべての とともにParts) を使用Session.Get(typeof(Unit)して取得することもできます。

問題: 複数のユニットを取得すると、Parts Dictionary.

疑似コードで言い換えられた問題:LoadMethodOfPartsDictionary = (Stepping with Debugger) ? Eagerly : Lazy;

次のコードは私を困惑させます。デバッガーを使用してステップ実行するとParts Dictionary、 aUnitが熱​​心に読み込まれます。しかし、return Units(ステップスルーではなく)に実行すると、NHibernateは突然Units = crit.Future<Unit>().ToList<Unit>();のように遅延ロードを望んでいるようです。Parts DictionaryNHibernate.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;
        }
    }
}

ヒントをいただければ幸いです。

PS 私は [Debugging] タグを使用しました。これは、このシナリオの鍵と思われるためです。

4

1 に答える 1

2

DB からデータを受け取る方法には、2 つの異なる概念があります。一対多(リスト、辞書)の場合。

1) NHibernate を呼び出して、ID または参照でデータを取得できます (同様のケース)。

session.Get<Unit>(1);

この場合、NHibernatesはlazyとしてマークされていないすべてのプロパティを注入します。したがって、あなたの場合、これにより、パーツも積極的にロードされます。

同様のものは参照プロパティです: public virtual Unit Unit { get; set; }of aneOtherObject

var otherObject = ... // get from session
var unit = otherObject.Unit; // the full Unit with all `Lazy="false"` properties is loaded

Criteria2)しかし、 (あなたの場合のように)も使用できます。ただし、これは異なるアプローチです。この場合、私たちは明示的に、Unit

Units = crit.Future<Unit>().ToList<Unit>();

これには多くの利点があります。

  • Unitテーブルでのみ効率的なページングを行うことができます
  • ユニットのみロードされます(パーツは使用されない可能性があります)
  • パーツが使用されている場合、それらは遅延ロードされます

しかし、本当に必要な場合(不正なページングなどの副作用に関係なく)、1 つの選択でパーツをロードすることもできます。

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

その瞬間から、Util は軽量になります。本当に必要になるまで、パーツはロードされません。リクエスト全体でセッションが開かれている場合、パーツがタッチされると、それらは 1 つの SELECT でロードされます (Utils のページ サイズが 25 より大きくない場合)。

このアプローチは非常に効率的です。ORM の力を利用しているためです。

于 2013-08-15T04:33:02.727 に答える