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

Posted

技术标签:

【中文标题】将实体框架对象序列化为 JSON【英文标题】:Serialize Entity Framework objects into JSON 【发布时间】:2010-10-14 01:31:37 【问题描述】:

似乎使用 WCF 的本机 DataContractJsonSerializer 或 ASP.NET 的本机 javascript 序列化程序都无法将 Entity Framework 对象序列化为 JSON。这是由于两个序列化程序都拒绝的引用计数问题。我也试过Json.NET,它在引用计数问题上也特别失败。


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


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

实际上,我在 https://blog.programx.co.uk/2009/03/18/wcf-json-serialization-woes-and-a-solution/ 上写过关于我所经历的各个步骤的博客

我是否遗漏了一些明显的东西?

【问题讨论】:

是的 JSon.NET 序列化,但我想返回 IQueryable 而不是 json 字符串!如果我返回 IQueryable,我可以使用 OData。 在 bloggingabout.net 上的链接。坏了 @MichaelFreidgeim 是的,当有人删除另一个帖子时,我意识到了这一点。这很好。似乎那个博客决定删除我的博客。不开心。我只能道歉。我花时间回顾了互联网档案并在不同的位置重新发布。 【参考方案1】:

我这样做的方法是将要序列化的数据投影为匿名类型并对其进行序列化。这确保了只有我在 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。

【讨论】:

优秀的解决方案。有没有可行的方法将 javascript 对象反序列化回 EF 对象? Samuel,默认模型绑定器一般可以应付EF类型。但我更喜欢反序列化为特定于编辑的模型,然后映射到 EF 类型。 当你必须返回一个实体列表时你会怎么做? @Prabhu,我帖子中的代码确实返回了一个列表。你试过了吗? 谢谢!我真的厌倦了为此将视图变成 dto 对象并弄乱我的图表。【参考方案2】:

Microsoft 在将 EF 对象转换为数据合同的方式上犯了一个错误。它们包括基类和反向链接。

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

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

【讨论】:

现在有一个选项可以使序列化单向化。当您发布此帖子时,该选项可能不存在。只是想我会添加它以防其他人将来遇到此问题。 @Yuck:请添加指向此功能信息的链接。 据我所知EF没有这样的设置。这仅适用于 Linq-to-SQL。【参考方案3】:

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

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

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

【讨论】:

【参考方案4】:

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

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

【讨论】:

【参考方案5】:

如果您想获得更好的代码一致性,另一种解决方案是使用 JavaScriptConverter,它将处理循环引用依赖关系并且不会序列化此类引用。

我在这里写过博客:

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

【讨论】:

我同意梅哈尔。我在这里的回答中扩展了您的示例以处理其他一些情况***.com/questions/4053161/… 链接失效 哦,我会尝试用新的来修复它【参考方案6】:

仅供参考,我找到了替代解决方案

您可以将父关系设置为私有,这样属性就不会在翻译过程中暴露出来,移除无限的属性循环

【讨论】:

【参考方案7】:

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

解决方案。在您的 edmx 窗口内。 - 右键添加代码生成项 - 选择代码选项卡 - 选择 EF 4x.POCOC 实体生成器

如果你没有看到它,那么你将不得不用 nuget 安装它,搜索 EF。

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

【讨论】:

【参考方案8】:

我通过仅从 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 编码是安全的... 希望有人会发现此解决方案有帮助。写起来很有趣:)

【讨论】:

以上是关于将实体框架对象序列化为 JSON的主要内容,如果未能解决你的问题,请参考以下文章

如何将具有嵌套属性的 JSON 对象反序列化为 Symfony 实体?

通过 Web 传输实体框架对象并通过 JSON 返回的最佳方式

Symfony - 将 json 反序列化为实体数组

将 Objective-C 对象序列化和反序列化为 JSON

如何覆盖属性的 JSON 序列化,将值序列化为字符串而不是对象?

将 Json 反序列化为实体框架无法将 int 转换为类型