2012-11-19 2 views
7

私はEntity Frameworkを初めて使用しており、コードファーストを使用してデータベースからエンティティを読み込む方法を学習しようとしています。Entity Frameworkコードでの関連するエンティティの循環的な読み込みを防止する方法

public class AuditEntry 
{ 
    public int AuditEntryID { get; set; } 

    [Required] 
    public string Message { get; set; } 

    // Navigation Properties 
    public int UserID { get; set; } 
    public virtual User User { get; set; } 
} 

私はDBContext持ってちょうど2つを公開:

public class User 
{ 
    public int UserID { get; set; } 

    [Required] 
    public string Name { get; set; } 

    // Navigation Properties 
    public virtual ICollection<AuditEntry> AuditEntries { get; set; } 
} 

各ユーザーは、簡単なメッセージが含まれているそれぞれの監査エントリのセットを持つことができます。

私のモデルは、ユーザが含まれていますテーブル:

public DbSet<User> Users { get; set; } 
public DbSet<AuditEntry> AuditEntries { get; set; } 

私がしたいのは、混乱を含むAuditEntryオブジェクトのリストをロードすることです年齢と、UserIDおよびNameプロパティを含む関連するUserオブジェクト。

List<AuditEntry> auditEntries = db.AuditEntries.ToList(); 

は、私は私のナビゲーションプロパティは、仮想としてマークされ、私は無限に深いオブジェクトグラフを取得し、遅延ロードを無効にしていない持っているので(各AuditEntryは、それぞれのAuditEntriesのリストが含まれているユーザーオブジェクトを、持っていますAuditEntriesなどのリストを含むUserオブジェクトが含まれています)

オブジェクトをシリアル化したい場合(Web APIの結果として送信する場合など)、これはうまくいかないでしょう。

モデルのナビゲーションプロパティから仮想キーワードを削除するか、this.Configuration.LazyLoadingEnabled = false;をDBContextに追加して、遅延読み込みを無効にしました。期待どおり、この結果、ユーザーがnullに設定されたAuditEntryオブジェクトのフラットなリストが生成されます。遅延ロードオフで

、私は熱心な負荷にそのようなユーザー試してみた:

var auditentries = db.AuditEntries.Include(a => a.User); 

が、これは、以前と同じ深さ/巡回結果になります。

逆参照/後続のナビゲーションプロパティを元のオブジェクトに戻してサイクルを作成することなく、1レベル深く読み込むことができます(ユーザーのIDと名前を含めるなど)。 (内部的に)これは生産

public dynamic GetAuditEntries() 
{ 
    var result = from a in db.AuditEntries 
       select new 
       { 
        a.AuditEntryID, 
        a.Message, 
        User = new 
        { 
         a.User.UserID, 
         a.User.Username 
        } 
       }; 

    return result; 
} 

賢明なようだ、次のSQL:

+0

'Include'はちょうどそれを行う必要があります。あなたは 'User.AuditEntries'が遅延読み込みではないと確信していますか? –

+0

コンテキストが破棄された後にオブジェクトをシリアル化するとどうなりますか? –

+0

私は最初は思っていましたが、それは怠惰な読み込みではないと思いました。すべてのナビゲーションプロパティから仮想キーワードを削除して、レイジーローディングを明示的に無効にすることは役に立ちません。 ナビゲーションのプロパティが両方向にあるためですユーザーにはAuditEntriesのリストがあり、AuditEntriesはそれが属するユーザーを定義します。私はAuditEntriesを照会してユーザー情報を含める必要がありますが、すべての最上位のAuditEntryオブジェクトに、そのユーザーの他のすべてのAuditEntriesのリストを含める必要はありません。 私は何が起こっているのか説明するのに苦労しているので、それは難しいです! –

答えて

2

は、多くのハッキングの後、私は私のLINQクエリで動的な戻り値の型と投影を使用して、次の潜在的な解決策を作ってみた

SELECT 
[Extent1].[AuditEntryID] AS [AuditEntryID], 
[Extent1].[Message] AS [Message], 
[Extent1].[UserID] AS [UserID], 
[Extent2].[Username] AS [Username] 
FROM [dbo].[AuditEntries] AS [Extent1] 
INNER JOIN [dbo].[Users] AS [Extent2] ON [Extent1].[UserID] = [Extent2].[UserID] 

これは私の後ろにある結果をもたらしますが、(実際のモデルでは私の例よりもはるかに複雑な実際のモデルでは)特に問題はありません。 。

利点

  • これは私に私返されたオブジェクトの正確な内容を超える多くの柔軟性を提供します。私は一般的に、クライアント側でUIインタラクション/テンプレートのほとんどを行っているので、モデルオブジェクトの複数のバージョンを作成しなければならないことがよくあります。私は一般に、ユーザがどのプロパティ(例えば、

  • これは、エンティティフレームワークがインテリジェントにクエリを構築し、私が選んだフィールドだけを選択できるようにします。これは、ユーザーの電子メールアドレスを低特権ユーザのブラウザに送信することを意味します。たとえば、各上位レベルのAuditEntryオブジェクト内では、User.UserIDとUser.Usernameは表示したいが、User.AuditEntriesは表示しません。私はこのAPIに基づいて強く型付けされたMVCのビューを作成することができませんでしたので、

デメリット

  • は私のウェブAPIから返される型はもはや強く型付けされません。それが起こるので、これは私の特定の場合には問題ではありません。

  • 大規模/複雑なモデルからこのように手動で投影すると、多くのコードが生成され、多くの作業が発生し、APIにエラーが発生する可能性があります。これは慎重にテストする必要があります。

  • APIメソッドはモデルの構造と緊密に結びついています。これはPOCOクラスに基づいて完全に自動化されていないため、モデルに加えられた変更はモデルをロードするコードに反映する必要があります。

インクルードの方法は?

私はまだ.Include()メソッドの使用について少し混乱しています。このメソッドは、関連するエンティティが指定されたエンティティとともに「熱心に読み込まれる」ように指定することを理解します。しかし、ナビゲーションのプロパティを関係の両側に配置して仮想としてマークする必要があるように見えるため、Includeメソッドはサイクルが作成されているように見え、その有用性に重大な悪影響を及ぼします(特にシリアル化する場合) 。私の場合は

「木」のような少しになります。

AuditEntry 
    User 
     AuditEntries * n 
      User * n 
       etc 

私はこのアプローチ、この方法または任意の他の洞察力でダイナミックな使用の影響についてのコメントを聞いて非常に興味があります。

+0

こんにちはMatt Wilson、 知識を共有してくれてありがとうございます。 私はdbsetの完全な型なしアクセスを構築しています。 公共T FINDENTITY 私は循環参照することなく、それらのすべてを含める必要があり (オブジェクトID、一覧が含まれます)。 これについてのヘルプは、 'new {...}'ではなく –

+0

で 'new AuditEntry {...}'を試しましたか?私は同様の理由から同様のパターンをいくつか使うことができました。明示的にインスタンスを作成すると、EntityFrameworkは結果セットのデコード時にインスタンス化するクラスをあまり気にしません。 – SingleNegationElimination

関連する問題