6

環境:

  • Code First、Entity Framework 4.3.1。
  • ユーザー ---- トピック、1対多の関係。
  • Userwith public virtual ICollection<Topic> CreatedTopicsNavigation プロパティ (遅延読み込み);
  • Topicpublic virtual User Creatorナビゲーション プロパティを使用。
  • DataServiceController : DbDataController<DefaultDbContext>、Web API ベータ版、ASP.NET MVC 4 ベータ版、シングル ページ アプリケーション。
  • Json シリアライゼーション用の System.Json。
  • Web API アクション:

    public IQueryable<Topic> GetTopics()
    {
        // return DbContext.Topics;                   // OK
        return DbContext.Topics.Include("Creator");   //With Exception
    }
    
  • 結果: 「未処理の Microsoft .net フレームワーク例外が w3wp.exe で発生しました」

ここでの問題は次のように思われます:両方のエンティティにナビゲーション プロパティを追加CreatedTopicsするべきではありません (循環参照が原因ですか?)。また、クラスのナビゲーション プロパティを削除すると、User再び OK になります。

したがって、上記のような同様のコンテキストで、ここに私の質問があります:

  1. 1 対多の関係でナビゲーション プロパティを処理する方法。
  2. さらに、多対多の関係はどうですか。それを 2 つの1 対多の関係に分割する必要がありますか。
  3. ナビゲーション プロパティを使用する際のベスト プラクティスと注意事項は何ですか?

私は多くの関連記事を読みましたが、まだ十分に明確ではありません:(、

助けてくれてありがとう!

ディーン

4

1 に答える 1

9

これは、コードファーストやEFの問題ではなく、シリアル化の問題です。オブジェクトグラフをWebAPIメッセージで渡される表現に変換するために使用されるシリアライザーは、デフォルトでは循環参照を処理できません。使用するメッセージ形式に応じて、Web APIはデフォルトで異なるシリアライザーを使用します。ここでは、WebAPIで使用されるデフォルトのシリアライザーとその変更方法について詳しく説明します。次のテキストは、DataContractJsonSerializerまたはDataContractSerializer(XMLシリアル化のデフォルトである必要があります)を使用していると想定していますが、JSON.NETでも同じことが可能です(JSONシリアル化のデフォルトである必要があります-JSONシリアル化は切り替えることDataContractJsonSerializerができますが、デフォルトのシリアライザーの方が優れています)。

それで、あなたは何ができますか?DataContract(IsReference = true)クラスに属性を付け、渡された各プロパティに属性を付けることで、これらの循環参照を追跡する必要があることをシリアライザーに伝えることができDataMemberます(JSON.NETでそれを実現する方法については、リンクされた記事を確認してください)。これにより、シリアライザーがサイクルを正しく認識できるようになり、理論的にはシリアル化が成功します。理論的には、これは遅延読み込みを使用しないことも要求するためです。そうしないと、予想よりもはるかに多くのデータをシリアル化できます(一部の壊滅的なシナリオでは、データベースのコンテンツ全体がシリアル化される可能性があります)。

遅延読み込みを有効にしてエンティティグラフをシリアル化すると、TopicとそのCreatorシリアル化もプロパティにアクセスします=>すべての関連トピックは遅延読み込みされてシリアル化によって処理され、シリアル化は新しく読み込まれたすべてのトピックにCreatedTopics引き続きアクセスします。Creatorこのプロセスは、遅延ロードするオブジェクトが他になくなるまで続きます。このため、エンティティをシリアル化するときに遅延読み込みを使用しないでください。

他のオプションは、シリアル化から後方参照を除外することです。シリアル化する必要がありますCreator。プロパティを属性(JSON.NETの場合)CreatedTopicsでマークできるように、シリアル化する必要はありません。問題は、すべてを返すためのWeb APIアクションもある場合、属性が原因でこれが機能しないことです。IgnoreDataMemberJsonIgnoreUserCreateTopics

最後のオプションはエンティティを使用していません。このオプションは通常、特定の操作の要件を満たす特別なDTOオブジェクトを作成し、操作内でエンティティとDTO間の変換を処理するWebサービスで使用されます(AutoMapperなどのツールを使用して可能)。

1対1、1対多、または多対多の関係の処理に違いはありません。両側にナビゲーションプロパティがある場合は、常にこの問題に対処する必要があります。

于 2012-07-03T18:39:16.223 に答える