3

NHibernate POCOオブジェクトからDTOを作成する必要があります。問題は、POCO オブジェクトに動的プロキシが含まれているため、DTO にコピーしてはならないことです。事前に転送する必要があるすべてのコレクションと参照を熱心にロードします。事前にロードしなかった参照コレクションのロードを NHibernate に開始させたくありません。

SOに関するいくつかの同様の質問には、次のいずれかの回答が寄せられました。

  1. Session.GetSessionImplementation().PersistenceContext.Unproxy(); を提案する
  2. 遅延読み込みをオフにすることを提案します。

私の理解によれば、プロキシを置き換えるために熱心な読み込みが発生するため、最初の提案は無関係です。実際には、それは機能しません。オブジェクト内のプロキシは削除されません。(理由は?)

2番目の提案は、遅延読み込みをオフにすると、すべての参照とコレクションが熱心に読み込まれ、基本的にDB全体が読み込まれるようです。遅延読み込みがオフで、コレクションをリクエストしていない場合、コレクションは読み込まれないと予想していました。(NHibernate がそのようなオプションを提供していないというのは正しいですか?)

流暢な構成で NHibernate 3.3.1 を使用しています。

主な質問を繰り返しますが、プロキシを含む POCO からコピーされた、プロキシのない DTO を作成する必要があります。これらのプロキシの背後にデータをロードしたくありません。

コード例を含み、ValueInjecter / AutoMapper を使用してプロセスを自動化する有益な提案は、非常に役立ちます。

編集#1:

プロジェクションを使用するという Roger Alsing の提案に従って、私が実際に探しているのは ValueInjecter のような規則ベースのマッピングであることに気付きました。これが理由です。最初に、私の DTO はモデルの POCO と同じように定義されます。これは、クライアント側プロジェクトで転送される既存の POCO に依存する大規模なコード ベースが原因です。

プロジェクションを使用して、フィールドのどのサブセットをコピーする必要があるかを指定する必要があります。このサブセットは、コンテキストごとに異なる可能性があります (理想的には、DTO が異なるため)。これは、2 番目のオプションが必要な場合に、サーバー側に導入される多くの新しいコードを意味します。

ValueInjecter を使用すると、特定のプロジェクションを記述したり、将来にわたってそれらを維持したりすることなく、1 回の呼び出しで規則に従って DTO を設定できます。つまり、ValueInjecter に Proxy オブジェクトを無視させることができればということです。

私の状況ではプロジェクションを使用することは良いが理想的な解決策ではないことを考えると、ValueInjecter のようなものを構成して、プロキシをコピーしたり、コピー時に熱心/遅延ロードをトリガーしたりせずに POCO をコピーする方法はありますか?

4

4 に答える 4

5

これを解決するには、Linq または O/R マッパーが持つクエリ言語を使用して、DTO をプロジェクションとして選択します。

例えば

return from c in customers 
       select new CustomerDTO 
       {
          Name = c.Name , 
          Orders = c.Orders.Select (o => new OrderDTO {...} ) 
       };

この方法では、リフレクション マジックやその他の凝ったものに頼る必要はありません。また、クエリは必要なものを一度にフェッチするため、エンティティをフェッチしてからメモリ内の DTO に変換するよりも、通常ははるかに効率的です。(結果の SQL クエリに何らかの理由で余分な結合が含まれている場合、場合によっては効率が低下する可能性があります..)

于 2012-08-05T15:07:44.333 に答える
2

AutoMapper で次の ValueResolver を使用しています。

/// <summary>
/// ValueResolver that will set NHibernate proxy objects to null, instead of triggering a lazy load of the object
/// </summary>
public class IgnoreNHibernateProxyValueResolver : IValueResolver
{
    public ResolutionResult Resolve(ResolutionResult source)
    {
        var prop = source.Type.GetProperty(source.Context.MemberName).GetValue(source.Value, null);
        var proxy = prop as INHibernateProxy;
        if (proxy != null && proxy.HibernateLazyInitializer.IsUninitialized)
        {
            return source.Ignore();
        }

        return source.New(prop);
    }
}
于 2013-08-28T16:45:39.863 に答える
1

NH 3.0 での QueryOver の概要でプロジェクションを見てください。

CatSummary summaryDto = null;
IList<CatSummary> catReport =
    session.QueryOver<Cat>()
        .SelectList(list => list
            .SelectGroup(c => c.Name).WithAlias(() => summaryDto.Name)
            .SelectAvg(c => c.Age).WithAlias(() => summaryDto.AverageAge))
        .TransformUsing(Transformers.AliasToBean<CatSummary>())
        .List<CatSummary>();
于 2012-08-05T13:45:02.247 に答える
1

ValueInjecter ソリューションの場合、SmartConventionInjection を使用することをお勧めします(リンク先のページからソリューションにコードをコピーする必要があります)。

プロキシのプロパティに触れない規則を指定した後

ここから始めます:

public class MapPoco: SmartConventionInjection
{
     protected override bool Match(SmartConventionInfo c)
     {
         return c.SourceProp.Name == c.TargetProp.Name;
     }
}
于 2012-08-05T15:19:21.363 に答える