似乎无法使用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/
时所采取的各个步骤我错过了一些明显的东西吗?
答案 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编码是安全的... 希望有人会发现这个解决方案很有用写它很有趣:)