2009-06-24 19 views
8

エンティティフレームワークオブジェクトをJavaScriptオブジェクト(JSON)にシリアル化するにはどうすればよいですか?私はJSON.NETを使用してみましたが、シリアル化しようとすると次の例外が発生します。Json.Netを使用してEntity Frameworkオブジェクトをシリアル化

例外:Newtonsoft.Json.JsonSerializationException、メッセージ=「自己参照ループ」

Hitesh

答えて

7

あなたが循環参照に関しては、元のDataContractシリアライザと同じ一般的な問題を抱えているように聞こえます。お互いを参照するオブジェクトはメモリ内のオブジェクトグラフとかなり共通していますが、このような循環参照は、シリアライザが特に考慮していない場合、シリアライズすると無限に再帰することは避けられません。共通の非バイナリシリアル化形式(XMLとJSONの2つが最も一般的です)で循環参照を処理する確立された標準はほとんどありません。

Microsoftは.NET 3.5でDataContractシリアライザの循環問題を解決しましたSP1では、XMLでrefセマンティクスを利用しています。私の知る限りでは、JSONのためのそのようなものはありません。これは、JSON.NETがあなたのオブジェクトグラフを直列化するのを妨げている理由かもしれません。

両方向ではなく片方向でナビゲート可能な参照のみがあることを確認します(つまり、親から子に、子から親には移動しません)。親子と子/親サイクリック参照の最も一般的なタイプです。また、下位レベルの子が最終的にグラフのルートを参照し、間接的な循環グラフを作成することもあります(ただし、これらは親/子ループよりもはるかに一般的です)。

1回あなたはあなたのオブジェクトグラフの循環参照を排除するなら、あなたは直列化できるはずです。

+0

感謝を:

var context = new YourEntities(); context.Configuration.ProxyCreationEnabled = false; var results = context.YourEntity.Take(100).ToList(); 

その後、安全に次のようにループするデフォルトの参照を省略してJSON.NETシリアライズされたデータを返すことができます。オブジェクトグラフの循環参照を取り除きたいとは思っていませんでした。なぜなら、それをどうやって行うのか、そしてこの変更を行うことの意義は何かを完全にはわからないからです。代わりに、単純な単純なオブジェクトを作成し、これらのオブジェクトにEntity Frameworkオブジェクトを使用し、プレーンオブジェクトをシリアライズすると正常に動作します。 – Hitesh

+4

一般的に言えば、実際には、ドメインエンティティとDTOを互いに独立した状態に保つための良い方法です。ネイティブで豊富なグラフ状態のエンティティは、ビジネス問題のドメインをモデル化してビジネス上の問題を解決する優れた方法ですが、サービス指向とシリアライゼーションには適していません。私の個人的な好みは、ビジネスをモデル化し、個々のシリアライズ可能なDTOを提供する独立したサービスAPIを提供するために、ドメインをできるだけ豊かで相互に関連づけておくことです。 – jrista

+0

この問題は、双方向ナビゲーションプロパティによって引き起こされた参照の単なるサイクルよりも大きくなります。まったく同じ依存オブジェクトをすべて参照する10個のオブジェクトがある場合はどうですか?参照されるオブジェクトを10回複製せずにこのグラフをシリアライズする標準的な方法は何ですか?そして、クライアント側でデータを正しくデシリアライズするこの同じトークンによって、10種類のオブジェクトの代わりに参照オブジェクトの1つのインスタンスを再作成しますか? JSONを使用したこれに対する標準または一般的なパターン – Marchy

4

私はこの問題を抱え、ループを引き起こすプロパティにNewtonsoft.Json.JsonIgnoreAttributeを追加して解決しました。明らかに、そのプロパティはシリアル化されません。この問題を解決するために、私は通常、外部参照IDと外部クラスの両方を自分のエンティティに持ちます。私はこれが直感的ではないことを理解していますが、それはJulia Lermanの書籍Programming Entity Framework:Code Firstで推薦された方法です。私はEntity Frameworkのいくつかの問題を円滑にするのに役立つことを発見しました。

public class SomeEntity 
{ 
     [JsonIgnore] 
     public ForeignEntity SomeForeignEntity {get;set;} 
     public Guid ForeignEntityId {get;set;} 
} 

更新:

dataContext.Configuration.ProxyCreationEnabled = false; 

あなたは(あなたがシリアライズされている場合は可能性が高いと思われる)サービスのためのコードを記述している場合:私は、私もそうのようなDbContextにプロキシを無効にするために必要な言及を忘れてしまいましたこれはおそらく問題ではありませんが、プロキシの作成が無効になっているときに失うものがいくつかあります。詳細はhttp://www.sellsbrothers.com/posts/Details/12665をご覧ください。

私はMSのWeb APIを使用していますので、私は私のコントローラを構築するとき、私はちょうど、プロキシの作成を無効にします。

public class MailingApiController : ApiController 
{ 
    public MailingApiController() 
    { 
     PreventDeepSerialization(); 
    } 

    private static void PreventDeepSerialization() 
    { 
     var dataContext = Injector.Get<IIntertwyneDbContext>(); 
     dataContext.Configuration.ProxyCreationEnabled = false; 
    } 
     .... 
1

これを回避するために、私はPOCOベースのコードファーストへの私のエンティティを変換します。これを行うには、edmxウィンドウ内を右クリックして、以下を選択します。

コード生成項目>コードタブ> EF POCOエンティティジェネレータを追加します。

ヌゲットが表示されていない場合は、インストールする必要があることに注意してください。

実行時に、EFは追跡のためにこれらのオブジェクトにプロキシクラスを追加しますが、シリアライゼーションプロセスが混乱する傾向があります。これを防ぐために、我々は単に次のようにfalseにProxyCreationEnabled設定することができます。あなたの答えのための

return JsonConvert.SerializeObject(results, Formatting.Indented, 
    new jsonSerializerSettings { 
     ReferenceLoopHandling = ReferenceLoopHandling.Ignore 
    }); 
関連する問題