如何在C#中使用JavascriptSerializer序列化嵌套实体(模型)?
我正在构建一个ASP.NET Web应用程序,而且我还将首先使用实体框架代码。在本例中,我使用两个实体(客户和联系人),它们彼此之间有一对多关系(一个客户可以有多个联系人)。从数据库中获取数据时,一切正常。我也使用Viewmodels,所以在我的数据实体旁边,我还有两个名为CustomerModel和ContactModel的模型 下面我将展示我的实体和视图模型: 客户实体如何在C#中使用JavascriptSerializer序列化嵌套实体(模型)?,c#,json,asp.net-mvc,nested,javascriptserializer,C#,Json,Asp.net Mvc,Nested,Javascriptserializer,我正在构建一个ASP.NET Web应用程序,而且我还将首先使用实体框架代码。在本例中,我使用两个实体(客户和联系人),它们彼此之间有一对多关系(一个客户可以有多个联系人)。从数据库中获取数据时,一切正常。我也使用Viewmodels,所以在我的数据实体旁边,我还有两个名为CustomerModel和ContactModel的模型 下面我将展示我的实体和视图模型: 客户实体 [Table("Customer")] public class Customer { [
[Table("Customer")]
public class Customer
{
[Key()]
public Guid Id { get; set; }
//other non-relevant properties
public virtual List<Contact> Contacts { get; set; }
}
客户模型
[Serializable]
public class CustomerModel
{
public Guid Id { get; set; }
//non-relevant properties
[ScriptIgnore(ApplyToOverrides = true)]
public virtual List<ContactModel> Contacts { get; set; }
}
当我运行我的应用程序和代码时,它在后端可以正常工作,直到它需要在我的HomeController中将其序列化为JSON
public ActionResult GetCustomerById(Guid id)
{
CustomerModel customer = new CustomerManager().GetById(id);
string output = serializer.Serialize(customer);
return Content(output);
}
即使是CustomerModel
对象也会获得2个联系人,但在我的Serialize(customer)
方法中,它不会将其解析为JSON
。所以实际上,当我调试它并查看输出时,我看到了每个属性,但没有看到嵌套的ContactModels
在我的例子中,
字符串输出
不包含两个联系人
。我如何解决这个问题?我也检查了一些关于Stackoverflow的“类似”问题,但没有结果。好的,我发现您缺少一个概念DTO和循环引用,简单来说,您必须为您想要交付的内容制作一个模型。让你头疼的是层/参照,所以我去掉了模型中的所有循环
想象一下a->b->a会导致json看起来像这样
{
a:b{a:b{a:b{a:b{a:b{a:b{a:b{a:b{a:b{a:b{a:b{a:b{a}}}//进入无穷远
}
这本质上就是你想要的
public JsonResult GetCustomerById(Guid id)
{
CustomerModel customer = new CustomerManager().GetById(id);
CustomerResultModel output = new CustomerResultModel(){
id = customer.Id,
Contacts = GetContacts(customer.Contacts)
};
return Json(output, JsonRequestBehavior.AllowGet);
//If you only POST then remove the AllowGet (the action name says Get so I'm assuming
}
private IEnumerable<ContactResultModel> GetContacts(Contacts){
foreach(var a in Contacts){
//When you use the yield keyword in a statement, you indicate that the method, operator, or get accessor in which it appears is an iterator.
yield return new ContactResultModel(){
Id = a.Id,
CustomerId = a.CustomerId
};
}
}
公共JsonResult GetCustomerById(Guid id)
{
CustomerModel customer=new CustomerManager().GetById(id);
CustomerResultModel输出=新CustomerResultModel(){
id=customer.id,
Contacts=GetContacts(customer.Contacts)
};
返回Json(输出,JsonRequestBehavior.AllowGet);
//如果您只发布,那么删除AllowGet(操作名称为Get,我假设是这样的)
}
private IEnumerable GetContacts(联系人){
foreach(触点中的var a){
//在语句中使用yield关键字时,可以指示它出现的方法、运算符或get访问器是迭代器。
返回新的ContactResultModel(){
Id=a.Id,
CustomerId=a.CustomerId
};
}
}
模型
class CustomerResultModel{
public Guid id {get;set;}
public IEnumerable<ContactResultModel> Contacts {get;set;}
}
class ContactResultModel{
public Guid id {get;set;}
public Guid CustomerId {get;set;}
}
类CustomerResultModel{
公共Guid id{get;set;}
公共IEnumerable联系人{get;set;}
}
类ContactResultModel{
公共Guid id{get;set;}
公共Guid CustomerId{get;set;}
}
首先,不要序列化实体(这就是为什么你有数据库,创建你自己的结构来序列化(读取数据传输对象(DTO))。其次,通过序列化这样的东西,你会得到循环引用。意思是A引用B引用A(循环到无穷大),这就是为什么你必须停止以下引用,在大多数情况下,停止多个链接或一个链接中的引用将起作用,在某些情况下,你必须同时阻止这两个链接。这意味着,是的,你将有点“错过”一些数据。JSON的复杂度有一个限制,这在SQL@ThomasAndreèLian因此,如果我正确理解您的答案,那么如果我以另一种方式构建视图模型,而不使用引用来正确存储我的属性,可能会有所帮助。您是否声称CustomerModel
和ContactModel
是视图模型?如果是,则ey将没有[Serializable]
或[ScriptIgnore]
属性,并且属性将不是虚拟的。除了循环引用问题(删除CustomerModel Customer
)之外,如果要返回Json,请使用返回Json(客户)
是的,删除实体中的所有序列化,它们永远不属于实体。(这是一个糟糕的开始)@ThomasAndreèLian谢谢你,也在我的viewmodels中?或者只是在我的数据库实体中称为“Customer”和“Contact”?我正在尝试这个atm,当我得到结果时,我会尽快回答,如果你需要结果模型中的更多数据,你可以添加,只是不要在你的数据中做循环引用,就像你在实体中可以做的那样(多个)这最终对我有效,但与你给我的示例不同。我试图真正理解DTO,它帮助我避免了循环引用的内容。但我所做的唯一更改是删除ContactModel类中的CustomerId和CustomerModel属性,以及删除的[ScriptIgnore(ApplyToOverrides=true)]在公共虚拟列表联系人{get;set;}属性上方。执行此操作后,它工作正常,还序列化了CustomerModel对象中嵌套的ContactModel实体。感谢您的帮助Thomas!这与我的模型基本相同(它们与您提供的相同,但没有链接的PropS)正如我提到的,有时候你只需要删除其中一个方向就可以成功
public JsonResult GetCustomerById(Guid id)
{
CustomerModel customer = new CustomerManager().GetById(id);
CustomerResultModel output = new CustomerResultModel(){
id = customer.Id,
Contacts = GetContacts(customer.Contacts)
};
return Json(output, JsonRequestBehavior.AllowGet);
//If you only POST then remove the AllowGet (the action name says Get so I'm assuming
}
private IEnumerable<ContactResultModel> GetContacts(Contacts){
foreach(var a in Contacts){
//When you use the yield keyword in a statement, you indicate that the method, operator, or get accessor in which it appears is an iterator.
yield return new ContactResultModel(){
Id = a.Id,
CustomerId = a.CustomerId
};
}
}
class CustomerResultModel{
public Guid id {get;set;}
public IEnumerable<ContactResultModel> Contacts {get;set;}
}
class ContactResultModel{
public Guid id {get;set;}
public Guid CustomerId {get;set;}
}