5

ValueInjecterを使用して、EntityFrameworkPOCOのディープクローンを同様のDTOクラスに作成する際に問題が発生しました。

複数の関連エンティティ/ナビゲーションプロパティを持つ子エンティティを持つ複雑なPOCOオブジェクトからやや単純なDTOに注入している場合、ValueInjecterはまだ複数のプロパティ値に触れており、データベースからこのデータの遅延読み込みが発生しているようです。

ValueInjecterは、指定されたターゲットに値を注入する準備をするときに、特定のソースオブジェクトのすべてのプロパティの値を取得すると思います。

私の実際のプロジェクトはかなり複雑ですが、例として、NerdDinnerの例を取り上げて、はるかに単純な方法で問題を再現しました。(NerdDinnerは、EF4を使用した最初の開発コードの例です(ScottGu NerdDinnerの例)。

したがって、2つのモデルクラスがあります。

public class Dinner
{
    public int DinnerId { get; set; }
    public string Title { get; set; }
    public DateTime EventDate { get; set; }
    public string Address { get; set; }
    public string HostedBy { get; set; }
    public virtual ICollection<RSVP> Rsvps { get; set; }
}

public class RSVP
{
    public int RsvpID { get; set; }
    public int DinnerID { get; set; }
    public string AttendeeEmail { get; set; }
    public virtual Dinner Dinner { get; set; }
}

DTOクラスも作成しました。

public class DinnerDTO
{ 
    public int DinnerId { get; set; }
    public string Title { get; set; }
    public DateTime EventDate { get; set; }
    public string Address { get; set; }
    public string HostedBy { get; set; }
}

にRsvpsコレクションがないことに注意DinnerしてくださいDinnerDTO

また重要なのは、オブジェクトのディープクローン作成にCloneInjection規則を使用していることです。このコードは、ここSOだけでなく、他の多くのサイトでも、ディープクローンインジェクションを実行するためのアプローチとして提案されています。このコードはここにあります:CloneInjectionコード

ここで、発生する遅延読み込みを強調するために、Id=1のディナーに10,000のRSVPを挿入しました。

次に、次のコードを実行します。

var dinner = nerdDinners.Dinners.Where(x => x.DinnerId == 1).FirstOrDefault();
DinnerDTO dinnerDTO = new DinnerDTO();
dinnerDTO.InjectFrom<CloneInjection>(dinner);

の行にブレークポイントを設定し、InjectFromそれをステップオーバーすると、10,000 RSVPを遅延ロードするため、かなりの遅延が発生します。Matchとメソッドの両方でCloneInjectionコードにブレークポイントを設定した場合、ロードラグSetValueが解決されるまで、どちらもヒットしません。これは、プロパティの遅延負荷を発生させているのはValueInjecterの内部にある必要があることを示していRSVPsます。

さて、上記のコードをこれに変更すると:(Includeクエリにを追加する)

var dinner = nerdDinners.Dinners.Where(x => x.DinnerId == 1).Include("RSVPs").FirstOrDefault();
DinnerDTO dinnerDTO = new DinnerDTO();
dinnerDTO.InjectFrom<CloneInjection>(dinner);

この変更により、RSVPのリストの「EagerLoad」が強制されます。予想どおり、ラグはクエリと一致し、ラインはInjectFromラグなしで過ぎ去ります。

StackOverflowに関する漠然と関連するいくつかの投稿を読みましたが、データコンテキストでLazyLoadingを無効にしてから有効にすることをお勧めするものもあります。私はそれを試しました、そしてそれがうまくいく間、それはかなり汚れたように感じました。

私はこの投稿(遅延読み込みや熱心な読み込みをトリガーせずにNHibernate POCOをDTOにコピーする)と関連コードを読みました。彼のアプローチは、プロパティが初期化されていないプロキシであるかどうかを判断し、何らかの方法でそれらを取り除くためにいくつかのNHibernateメソッドを使用しているようです。EF4で似たようなものを見つけることができませんでした。

私を本当につまずかせるのは、Rsvpsコレクションが私のDTOオブジェクトにも含まれておらず、その値にも興味がないということです。これは私には正しくないようです。ValueInjecterコードは、ターゲットオブジェクトが気にしない可能性のあるプロパティの値を問い合わせるべきではないと思います。

ValueInjecterでこの動作をオーバーライドできる方法はありますか?どういうわけか、 ?のSetValueメソッドのように、値が必要であることが絶対に確実になるまで、プロパティ値の評価を延期します。ConventionInjectionそうすれば、少なくとも、私のDTOが望まないプロパティを評価することはありません。

私が考えることができる最善の解決策は、ValueInjecterまたはカスタム規則を使用して、アンロードされた遅延読み込みプロパティを何らかの方法で検出できるようにすることです。評価する代わりに、ターゲットでそのプロパティをnullに設定します。しかし、それは不可能だと思います。

私が使用すべきEFを介したより良いアプローチはありますか?データベース内のすべてを熱心にロードしたくありません。

私は完全にオフになっていて、問題はValueInjecterにはまったくありませんか?

*編集* 私は解決策を見つけてこの質問に答えました、私がそれを間違っているだけなのか、それとももっと良いアプローチがあるのか​​、私はまだ興味があります。

4

1 に答える 1

5

自分の質問に対して満足のいく答えを見つけたような気がするので、これを自分で締めくくります。私は2つのことをすることになった。

まず、dbContextで遅延読み込みを完全に無効にしました。dbContextコンストラクターでこれに似たもの。

this.Configuration.LazyLoadingEnabled = false;

私はEFのレイジーロード機能を実際には使用していなかったので、それをオフにしても大きな損失はありませんでした。これは、関連するエンティティにデータを入力する場合はInclude、クエリでそれらを指定する必要があることを意味します。大きな問題ではない。

私が行ったもう1つのことは、ディープクローンインジェクションの規則を作り直して、SmartConventionInjectionソースSmartConventionInjectionにあるコードを使用することでした。ベースインジェクションよりもさらに高速なインジェクションであることに加えて、呼び出しまでプロパティ値に影響を与えないため、遅延読み込みプロパティがあったとしても、DTOにもそのプロパティがない限り、プロパティ値には影響しません。SetValue

于 2013-02-10T19:28:24.373 に答える