将entity framework对象序列化为JSON

看起来,使用WCF的本地DataContractJsonSerializer或ASP.NET的本地JavaScript序列化程序将entity framework对象序列化为JSON是不可能的。 这是由于序列化器拒绝的引用计数问题。 我也试过Json.NET ,它也没有具体的引用计数问题。


编辑: Json.NET现在可以序列化和反序列化entity framework实体 。


我的对象是entity framework对象,重载执行额外的业务function(如身份validation等),我不想装饰这些类与特定于平台的属性等,因为我想呈现一个平台无关的API 。

我实际上在http://bloggingabout.net/blogs/program.x/archive/2009/03/18/wcf-json-serialization-woes.aspx上写了个博客。

我错过了什么明显的东西?

我这样做的方式是将我想要序列化的数据投影到一个匿名types并序列化。 这确保了只有我在JSON中实际需要的信息才被序列化,并且我不会无意中序列化对象图下方的某些内容。 它看起来像这样:

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

我发现匿名types是非常理想的。 显然,JSON并不关心用什么types来生成它。 匿名types为您提供了完全的灵活性,以便您将哪些属性和结构放入JSON中。

微软在将EF对象制作成数据合同的方式上犯了一个错误。 他们包括基础类和后面的链接。

最好的办法是为每个想要返回的实体创build相应的数据传输对象类。 这些将只包括数据,而不包括行为,而不包括实体的特定于EF的部分。 你也可以创build方法来翻译你的DTO类。

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

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

所以在我的模型中,我select了关系,并将Parent引用改为Internal,而不是Public。

可能不是一个理想的解决scheme,但为我工作。

如果您希望获得更好的代码一致性,另一个解决scheme是使用JavaScriptConverter,它将处理循环引用依赖性,并且不会序列化这些引用。

我在这里发表了博文

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

仅供参考我find了一个替代scheme

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

我为这个问题奋斗了好几天,

解。 在你的edmx窗口中。 – 右键单击​​并添加代码生成项目 – select代码选项卡 – selectEF 4x.POCOC实体生成器

如果你没有看到它,那么你将不得不安装它与nuget,searchEF。

实体生成器将生成所有复杂types和实体对象到简单的类中,以序列化成json。

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

它看起来很复杂,但是这是唯一一个为我工作的通用解决scheme…我正在使用这个逻辑作为我正在做的一个帮手,所以这是一个特殊的用途,我需要能够拦截每个对象types实体对象,也许有人可以适应他的使用。

 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编码…希望有人会觉得这个解决scheme有帮助。 这很有趣写它:)

基于@Craig Stuntz答案和DTO类似,对于我的解决scheme,我已经创build了一个模型的部分类(在一个单独的文件中)和一个返回对象方法,我只需要使用它将需要的属性。

 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(); 

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