web-dev-qa-db-ja.com

Entity FrameworkオブジェクトをJSONにシリアル化します

WCFのネイティブDataContractJsonSerializerまたはASP.NETのネイティブJavaScriptシリアライザーを使用して、Entity FrameworkオブジェクトをJSONにシリアル化することはできないようです。これは、両方のシリアライザーが拒否する参照カウントの問題によるものです。また、 Json.NET を試しましたが、これも参照カウントの問題で特に失敗します。


編集:Json.NETは、Entity Frameworkエンティティを シリアライズおよびデシリアライズできるようになりました


私のオブジェクトは、追加のビジネス機能(認証など)を実行するためにオーバーロードされるEntity Frameworkオブジェクトであり、プラットフォームに依存しないAPIを提示したいため、これらのクラスをプラットフォーム固有の属性などで装飾したくない。

私は実際に https://blog.programx.co.uk/2009/03/18/wcf-json-serialization-woes-and-a-で行った個々の手順についてブログに書きました解決/

明らかな何かを見逃していませんか?

45
Program.X

これを行う方法は、シリアル化するデータを匿名型に投影し、シリアル化することです。これにより、JSONで実際に必要な情報のみがシリアル化され、オブジェクトグラフのさらに下で何かを誤ってシリアル化することはありません。次のようになります。

var records = from entity in context.Entities
              select new 
              {
                  Prop1 = entity.Prop1,
                  Prop2 = entity.Prop2,
                  ChildProp = entity.Child.Prop
              }
return Json(records);

私はこれにほぼ理想的な匿名型を見つけます。 JSONは、明らかに、どのタイプがそれを生成するために使用されたかを気にしません。また、匿名型を使用すると、JSONにどのプロパティと構造を配置するかに関して完全な柔軟性が得られます。

72
Craig Stuntz

@Craig Stuntzの回答に基づいており、DTOに似ていますが、私のソリューションでは、モデルの部分的なクラス(別のファイルに)と戻りオブジェクトメソッドを作成し、必要なプロパティのみを使用してそれをどのようにしたいのですか?.

namespace TestApplication.Models
{
    public partial class Employee
    {
        public object ToObject()
        {
            return new
            {
                 EmployeeID = EmployeeID,
                 Name = Name,
                 Username = Username,
                 Office = Office,
                 PhoneNumber = PhoneNumber,
                 EmailAddress = EmailAddress,
                 Title = Title,
                 Department = Department,
                 Manager = Manager
            };
        }
    }
}

そして、私は単に帰りにそれを呼び出します:

var employee = dbCtx.Employees.Where(x => x.Name == usersName).Single();
return employee.ToObject();

受け入れられた答えはより迅速かつ簡単であると思います。私は自分の方法を使用して、すべてのリターンの一貫性と乾燥を維持します。

2
Pat Migliaccio

私の解決策は、子エンティティの親参照を単に削除することでした。

そのため、私のモデルでは、リレーションシップを選択し、親参照をパブリックではなく内部に変更しました。

すべての人にとって理想的なソリューションではないかもしれませんが、私にとってはうまくいきました。

2
Anthony Main

コードの一貫性を向上させるためのもう1つの解決策は、循環参照の依存関係を処理し、そのような参照をシリアル化しないJavaScriptConverterを使用することです。

私はここについてブログに書きました:

http://hellowebapps.com/2010-09-26/produce-json-from-entity-framework-4-0-generated-classes/

1
Mehal

System名前空間からオブジェクト型のみを取得し、それらを辞書に変換してからリストに追加することで解決しました。私にとってはうまくいく:)

それは複雑に見えますが、これは私のために働いた唯一の一般的なソリューションでした...私は作っているヘルパーにこのロジックを使用しているので、すべてのオブジェクトタイプをインターセプトする必要がある特別な用途のためですエンティティオブジェクト、おそらく誰かがそれを自分の使用に適応させることができます。

List<Dictionary<string, string>> outputData = new List<Dictionary<string, string>>();

// convert all items to objects
var data = Data.ToArray().Cast<object>().ToArray();

// get info about objects; and get only those we need
// this will remove circular references and other stuff we don't need
PropertyInfo[] objInfos = data[0].GetType().GetProperties();
foreach (PropertyInfo info in objInfos) {
    switch (info.PropertyType.Namespace)
    { 
          // all types that are in "System" namespace should be OK
          case "System":
              propeties.Add(info.Name);
              break;
     }
}
Dictionary<string, string> rowsData = null;
foreach (object obj in data) {
     rowsData = new Dictionary<string, string>();
     Type objType = obj.GetType();
     foreach (string propertyName in propeties)
     {
//if You don't need to intercept every object type You could just call .ToString(), and remove other code
         PropertyInfo info = objType.GetProperty(propertyName);
         switch(info.PropertyType.FullName)
         {
               case "System.String":
                    var colData = info.GetValue(obj, null);
                    rowsData.Add(propertyName, colData != null ? colData.ToString() : String.Empty);
                    break;
//here You can add more variable types if you need so (like int and so on...)
           }
      }

      outputData .Add(rowsData); // add a new row
}

"outputData"はJSONエンコードに対して安全です...このソリューションが役立つと思います。それを書くのは楽しかったです:)

1
Tom

参考までに、別の解決策を見つけました

親関係をプライベートとして設定すると、変換中にプロパティが公開されず、無限プロパティループが削除されます。

1
Anthony Main

私はこの問題と数日間戦いましたが、

解決。 edmxウィンドウ内。 -右クリックしてコード生成項目を追加-[コード]タブを選択-EF 4x.POCOC Entity Generatorを選択

表示されない場合は、nugetでインストールする必要があります。EFを検索してください。

エンティティジェネレーターは、複雑な型とエンティティオブジェクトをすべて単純なクラスに生成し、jsonにシリアル化します。

1
Tebza