将实体框架对象序列化为JSON

时间:2009-03-18 11:53:49

标签: wcf json entity-framework asp.net-ajax

似乎无法使用WCF的本机DataContractJsonSerializer或ASP.NET的本机JavaScript序列化程序将Entity Framework对象序列化为JSON。这是由于序列化器拒绝的引用计数问题。我也尝试了Json.NET,它也没有专门针对参考计数问题。


编辑:Json.NET现在可以serialize and deserialize Entity Framework entities


我的对象是实体框架对象,它们被重载以执行其他业务功能(例如,身份验证等),我不想用平台特定的属性等来装饰这些类,因为我想呈现一个平台-agnostic API。

我实际上是在博客上写过我在https://blog.programx.co.uk/2009/03/18/wcf-json-serialization-woes-and-a-solution/

时所采取的各个步骤

我错过了一些明显的东西吗?

8 个答案:

答案 0 :(得分:72)

我这样做的方法是将我要序列化的数据投影到匿名类型并序列化。这确保只有我在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中的属性和结构的完全灵活性。

答案 1 :(得分:16)

Microsoft将EF对象转换为数据合同的方式出错。它们包括基类和反向链接。

您最好的选择是为要返回的每个实体创建等效的数据传输对象类。这些仅包括数据,而不包括行为,而不包括实体的EF特定部分。您还可以创建与DTO类进行转换的方法。

然后,您的服务将返回数据传输对象。

答案 2 :(得分:2)

我的解决方案是简单地删除子实体上的父引用。

所以在我的模型中,我选择了关系并将父引用更改为内部而不是公共。

可能不是一个理想的解决方案,但对我有用。

答案 3 :(得分:2)

基于@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();

我认为接受的答案更加快捷方便,我只是使用我的方法来保持所有回报的一致性和干燥。

答案 4 :(得分:1)

如果您希望获得更好的代码一致性,还有一个解决方案是使用JavaScriptConverter,它将处理循环引用依赖项,并且不会序列化此类引用。

我在这里写博客:

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

答案 5 :(得分:1)

仅供参考我找到了另一种解决方案

您可以将父关系设置为私有,以便在翻译期间不会公开属性,从而删除无限属性循环

答案 6 :(得分:1)

我和这个问题斗争了好几天,

解。在你的edmx窗口里面。 - 右键单击​​并添加代码生成项 - 选择代码选项卡 - 选择EF 4x.POCOC实体生成器

如果你没有看到它,那么你必须用nuget安装它,搜索EF。

实体生成器会将所有复杂类型和实体对象生成为简单类,以序列化为json。

答案 7 :(得分:1)

我通过从System命名空间中仅获取对象类型来解决它,然后将它们转换为Dictionary,然后将它们添加到列表中。对我有用:))

看起来很复杂,但这是唯一对我有用的通用解决方案...... 我正在使用这个逻辑作为我正在制作的帮助器,所以它是一个特殊的用途,我需要能够拦截实体对象中的每个对象类型,也许有人可以使它适应他的使用。

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编码是安全的... 希望有人会发现这个解决方案很有用写它很有趣:)

相关问题