代码优先- JSON循环引用序列化错误
本文关键字:引用 序列化 错误 循环 JSON 代码 | 更新日期: 2023-09-27 17:49:15
我得到一个循环引用序列化错误,虽然,据我所知,我没有任何循环引用。我正在从数据库中检索一组订单,并将它们作为JSON发送到客户端。所有代码如下所示。
错误:
误差
检测到循环引用类型的对象序列化时"System.Data.Entity.DynamicProxies.Order_83CECF2AA4DE38232F9077D4B26941AB96BC61230419EA8AC42C9100E6072812"。描述:一个未处理的异常的执行过程中发生当前的web请求。请参阅堆栈跟踪以获取有关的更多信息错误和它的起源代码。
异常细节:系统。InvalidOperationException:检测到循环引用类型的对象序列化"System.Data.Entity.DynamicProxies.Order_83CECF2AA4DE38232F9077D4B26941AB96BC61230419EA8AC42C9100E6072812"。
源错误:
生成了一个未处理的异常在当前执行期间web请求。有关异常的来源和位置是否可以使用异常来识别
我的课程如下:
为
public class Order
{
[Key]
public int OrderId { get; set; }
public int PatientId { get; set; }
public virtual Patient Patient { get; set; }
public int CertificationPeriodId { get; set; }
public virtual CertificationPeriod CertificationPeriod { get; set; }
public int AgencyId { get; set; }
public virtual Agency Agency { get; set; }
public int PrimaryDiagnosisId { get; set; }
public virtual Diagnosis PrimaryDiagnosis { get; set; }
public int ApprovalStatusId { get; set; }
public virtual OrderApprovalStatus ApprovalStatus { get; set; }
public int ApproverId { get; set; }
public virtual User Approver { get; set; }
public int SubmitterId { get; set; }
public virtual User Submitter { get; set; }
public DateTime ApprovalDate { get; set; }
public DateTime SubmittedDate { get; set; }
public Boolean IsDeprecated { get; set; }
}
病人
public class Patient
{
[Key]
public int PatientId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string MiddleInitial { get; set; }
public bool IsMale;
public DateTime DateOfBirth { get; set; }
public int PatientAddressId { get; set; }
public Address PatientAddress { get; set; }
public bool IsDeprecated { get; set; }
}
认证期
public class CertificationPeriod
{
[Key]
public int CertificationPeriodId { get; set; }
public DateTime startDate { get; set; }
public DateTime endDate { get; set; }
public bool isDeprecated { get; set; }
}
机构
public class Agency
{
[Key]
public int AgencyId { get; set; }
public string Name { get; set; }
public int PatientAddressId { get; set; }
public virtual Address Address { get; set; }
}
诊断strong>
public class Diagnosis
{
[Key]
public int DiagnosisId { get; set; }
public string Icd9Code { get; set; }
public string Description { get; set; }
public DateTime DateOfDiagnosis { get; set; }
public string Onset { get; set; }
public string Details { get; set; }
}
OrderApprovalStatus
public class OrderApprovalStatus
{
[Key]
public int OrderApprovalStatusId { get; set; }
public string Status { get; set; }
}
用户
public class User
{
[Key]
public int UserId { get; set; }
public string Login { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string NPI { get; set; }
public string Email { get; set; }
}
<注:地址类是编辑时新增的
地址/strong>
public class Address
{
[Key]
public int AddressId { get; set; }
public string StreetAddress { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
public string Phone { get; set; }
public string Title { get; set; }
public string Label { get; set; }
}
执行序列化的代码在这里:
节选自OrderController
public ActionResult GetAll()
{
return Json(ppEFContext.Orders, JsonRequestBehavior.AllowGet);
}
谢谢
你可以尝试从所有导航属性中删除virtual
关键字来禁用延迟加载和代理创建,然后使用急切加载来显式加载所需的对象图:
public ActionResult GetAll()
{
return Json(ppEFContext.Orders
.Include(o => o.Patient)
.Include(o => o.Patient.PatientAddress)
.Include(o => o.CertificationPeriod)
.Include(o => o.Agency)
.Include(o => o.Agency.Address)
.Include(o => o.PrimaryDiagnosis)
.Include(o => o.ApprovalStatus)
.Include(o => o.Approver)
.Include(o => o.Submitter),
JsonRequestBehavior.AllowGet);
}
参考你之前的文章,看起来你的应用程序不依赖于延迟加载,因为你在那里引入了虚拟属性来延迟加载对象图,现在可能会导致序列化问题。
编辑
没有必要从导航属性中删除virtual
关键字(这将使模型完全不可能进行延迟加载)。对于干扰代理的特定情况,例如序列化,禁用代理创建(也禁用延迟加载)就足够了:
ppEFContext.Configuration.ProxyCreationEnabled = false;
禁用仅针对特定的上下文实例ppEFContext
创建代理。
当您知道您需要从特定上下文中序列化时,您可以像下面这样禁用该特定查询的代理创建。这对我来说很有效,比修改我的模型课要好。
using (var context = new MeContext())
{
context.Configuration.ProxyCreationEnabled = false;
return context.cars.Where(w => w.Brand == "Ferrari")
}
这种方法去掉了上下文的这个特定实例的代理对象类型,因此返回的对象是实际的类,因此序列化不是问题。
ie:{Models.car}
代替
{System.Data.Entity.DynamicProxies.car_231710A36F27E54BC6CE99BB50E0FE3B6BD4462ECA19695CD1BABB79605296EB}
问题是,您实际上是序列化实体框架生成的代理对象。不幸的是,这在与JSON序列化器一起使用时会出现一些问题。出于JSON兼容性的考虑,您可以考虑将实体映射到特殊的简单POCO类。
有一个属性要添加到实体框架对象
[ScriptIgnore]
这使得代码不执行循环引用。
我想他们已经在最新版本中修复了这个问题。
查看帮助文档"序列化和反序列化JSON ->序列化和保留对象引用"一节。
在初始化JSON时设置此设置。净序列化器:
PreserveReferencesHandling = PreserveReferencesHandling.Objects;
一个例子是:
var serializerSettings = new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects };
string json = JsonConvert.SerializeObject(people, Formatting.Indented, serializerSettings);
我验证了这适用于我的代码第一个解决方案,以及导航属性中的循环引用。如果您查看结果JSON,它应该到处都有"$id"answers"$ref"属性。
另一个解决方案是使用匿名类型作为LINQ查询的结果。
在我的项目中,我广泛使用延迟加载,禁用它不是正确的事情。
另一种解决方案是,如果只需要对象中的某些值,则构建一个匿名类并返回它,如下面的示例:
public JsonResult AjaxFindByName(string term)
{
var customers = context.Customers
.Where(c => c.Name.ToUpper().Contains(term.ToUpper())).Take(10)
.AsEnumerable()
.Select(c => new {
value = c.Name,
SSN = String.Format(@"{0:000'-00'-0000}", c.SSN),
CustomerID = c.CustomerID });
return Json(customers, JsonRequestBehavior.AllowGet);
}
循环引用的发生是因为你在对象上使用了即时加载。
你有两个方法:
- 在加载查询(linq或lambda)时关闭急切加载dbcontext . configuration . proxycreateenabled = false;
- 从Domainmodel 中删除虚拟关键字
- 分离对象(=没有即时加载功能&没有代理)
- Repository.Detach (entityObject)
- DbContext.Entry (entityObject)。EntityState = EntityState。分离
- 克隆属性
- 你可以使用像AutoMapper这样的东西来克隆对象,不要使用iclonable接口,因为它也克隆对象中的ProxyProperties,所以这将不起作用。
- 如果您正在构建API,请尝试使用具有不同配置的单独项目(不返回代理)
p。代理是EF从实体框架加载时创建的对象。简而言之:这意味着它保存原始值和更新的值,以便稍后更新它们。它处理其他事情;-)
对于使用代理EF/Linq2SQL类的人,我的解决方案是简单地删除我的子实体上的父引用。
因此,在我的模型中,我选择了关系,并将Parent引用更改为Internal而不是Public。
可能不是一个理想的解决方案,但对我有效。
可以删除virtual
关键字:
public virtual Patient Patient { get; set; }
-> public Patient Patient { get; set; }
请记住,当您删除virtual关键字时,延迟加载将被关闭。
我可以使用下面描述的方法来解决这个问题:
http://mytechworld.officeacuity.com/index.php/2010/02/serializing-entity-framework-objects-into-json-using-asp-net-mvc/