我收到循环参考序列化错误,但据我所知,我没有任何循环引用。我正在从数据库中检索一组订单并将它们作为JSON发送到客户端。所有代码如下所示。
这是错误:
错误
检测到循环参考 在序列化类型的对象时 'System.Data.Entity.DynamicProxies.Order_83CECF2AA4DE38232F9077D4B26941AB96BC61230419EA8AC42C9100E6072812'。 描述:未处理的异常 在执行期间发生 当前的网络请求。请查看 堆栈跟踪以获取更多信息 错误及其来源 代码。
异常详细信息: System.InvalidOperationException:A 检测到循环引用 序列化类型的对象 'System.Data.Entity.DynamicProxies.Order_83CECF2AA4DE38232F9077D4B26941AB96BC61230419EA8AC42C9100E6072812'。
来源错误:
生成了未处理的异常 在执行当前 网络请求。有关的信息 异常的起源和位置 可以使用例外来识别 堆栈跟踪下面。
我的课程如下:
顺序
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; }
}
诊断
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; }
}
注意:地址类别是编辑过程中的新增内容
地址
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);
}
由于
答案 0 :(得分:48)
您可以尝试从所有导航属性中删除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);
}
参考你的previous post,你的应用程序看起来并不依赖于延迟加载,因为你在那里引入了虚拟属性来懒散加载对象图,可能导致序列化问题。
修改强>
没有必要从导航属性中删除virtual
关键字(这会使模型完全无法进行延迟加载)。它足以禁用代理创建(也禁用延迟加载),用于代理令人不安的特定情况,如序列化:
ppEFContext.Configuration.ProxyCreationEnabled = false;
这仅禁用特定上下文实例ppEFContext
的代理创建。
(我刚刚看到,@ WillC已经在这里提到过了。请为此编辑提供支持请回答他。)
答案 1 :(得分:41)
如果您知道需要从特定上下文序列化,则可以禁用该特定查询的代理创建,如下所示。这对我有用,并且比修改我的模型类更好。
using (var context = new MeContext())
{
context.Configuration.ProxyCreationEnabled = false;
return context.cars.Where(w => w.Brand == "Ferrari")
}
此方法取消了此特定上下文实例的代理对象类型,因此返回的对象是实际的类,因此序列化不是问题。
即:
{Models.car}
而不是
{System.Data.Entity.DynamicProxies.car_231710A36F27E54BC6CE99BB50E0FE3B6BD4462ECA19695CD1BABB79605296EB}
答案 2 :(得分:9)
问题在于您实际上正在序列化实体框架生成的代理对象。不幸的是,当与JSON序列化程序一起使用时,这会出现一些问题。为了JSON兼容性,您可以考虑将实体映射到特殊的简单POCO类。
答案 3 :(得分:8)
有一个要添加到Entity Framework对象的属性
[ScriptIgnore]
这使代码不执行循环引用。
答案 4 :(得分:7)
我认为他们已经在最新版本中解决了这个问题。
查看“序列化和反序列化JSON - >序列化和保留对象引用”部分下的help docs。
初始化JSON.Net Serializer时设置此设置:
PreserveReferencesHandling = PreserveReferencesHandling.Objects;
一个例子是:
var serializerSettings = new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects };
string json = JsonConvert.SerializeObject(people, Formatting.Indented, serializerSettings);
我确认这适用于我的代码第一个解决方案,以及导航属性中的循环引用。如果你看看生成的JSON,它应该在任何地方都有“$ id”和“$ ref”属性。
答案 5 :(得分:6)
另一种解决方案是使用匿名类型作为LINQ查询的结果。
在我的项目中,我正在广泛使用延迟加载,禁用它不是正确的做法。
答案 6 :(得分:3)
另一种解决方案,如果只需要来自对象的某些值,则构建一个匿名类并返回它,如下例所示:
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);
}
答案 7 :(得分:2)
循环引用的发生是因为您在对象上使用了预先加载。
您有几种方法:
PS。代理是EF从实体框架加载时创建的对象。简而言之:它意味着它保存原始值和更新值,以便以后更新。它处理其他事情; - )
答案 8 :(得分:0)
对于使用代理EF / Linq2SQL类的人,我的解决方案是简单地删除子实体上的父引用。
所以在我的模型中,我选择了关系并将父引用更改为内部而不是公共。
可能不是一个理想的解决方案,但对我有用。
答案 9 :(得分:0)
您可以删除virtual
关键字:
public virtual Patient Patient { get; set; }
- > public Patient Patient { get; set; }
请注意,删除虚拟关键字时,将关闭延迟加载。
答案 10 :(得分:0)