如何序列化与Entity Framework具有一对多关系的实体?(How to serialize entities that have a one

编程入门 行业动态 更新时间:2024-10-23 21:36:05
如何序列化与Entity Framework具有一对多关系的实体?(How to serialize entities that have a one-to-many relationship with Entity Framework?)

我正在遵循Code First方法创建一个带有Entity Framework的ASP.NET Web API。 我有一个非常简单的模型,它由一个房子和一个房间之间的一对多关系组成:

House.cs

public class House { public int ID { get; set; } public string Address { get; set; } public virtual ICollection<Room> Rooms { get; set; } public House() { Rooms = new List<Room>(); } }

Room.cs

public class Room { public int ID { get; set; } public string Name { get; set; } public int HouseID { get; set; } public virtual House House { get; set; } }

我故意将虚拟关键字添加到House类的Rooms属性和Room类中的House属性,因为我希望能够查看House咨询House时所有的房间,我希望看到当我咨询房间(懒惰装载)时房间的房子。

但是,当我向控制器发出GET请求时,实体的序列化失败,并返回一个充满错误的XML(或JSON):

api / houses(使用Lazy Loading)

<Error> <Message>An error has occurred.</Message> <ExceptionMessage> The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'. </ExceptionMessage> <ExceptionType>System.InvalidOperationException</ExceptionType> <StackTrace/> <InnerException> <Message>An error has occurred.</Message> <ExceptionMessage> Type 'System.Data.Entity.DynamicProxies.House_49DC0BEAA9C67FACDA33CEE81852FA2D80C04F62C6838F92ACD2A490CECF86B5' with data contract name 'House_49DC0BEAA9C67FACDA33CEE81852FA2D80C04F62C6838F92ACD2A490CECF86B5:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies' is not expected. Consider using a DataContractResolver if you are using DataContractSerializer or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to the serializer. </ExceptionMessage> ... </Error>

如果我通过从属性中删除虚拟关键字来“禁用”延迟加载,则实体会被正确序列化,但我无法再访问关联的实体。 如果我要求获取所有房屋的GET请求,我将无法再访问House的房间:

api / houses(没有延迟加载)

<ArrayOfHouse xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/REM.Models"> <House> <Address>Boaty McBoatface Street 123</Address> <ID>1</ID> <Rooms/> </House> </ArrayOfHouse>

我尝试使用Eager Loading通过删除虚拟关键字并在Houses控制器的GET方法中显式加载Rooms来解决我的问题,如下所示:

HousesController.cs

public IQueryable<House> GetHouses() { return db.Houses.Include(r => r.Rooms); }

但它仍然无法序列化XML / JSON,向我显示与我尝试使用延迟加载进行GET请求时完全相同的错误消息。

我知道所有这些问题都可能与我的两个实体之间可能发生的循环依赖有关,但我不知道如何解决它。 因此,在一个问题中总结所有这些:

有没有办法提出一个请求,将返回所有房屋及其各自的房间,(不使用辅助POCO(DTO))?

I'm creating an ASP.NET Web API with Entity Framework following the Code First Approach. I have a very simple model, which consists of a one-to-many relationship between a House and a Room:

House.cs

public class House { public int ID { get; set; } public string Address { get; set; } public virtual ICollection<Room> Rooms { get; set; } public House() { Rooms = new List<Room>(); } }

Room.cs

public class Room { public int ID { get; set; } public string Name { get; set; } public int HouseID { get; set; } public virtual House House { get; set; } }

I have purposely added the virtual keyword to the Rooms attribute in the House class and to the House attribute in the Room class because I want to be able to see all the Rooms that a House has when I consult a House, and I want to see the House of a Room when I consult said Room (Lazy Loading).

However, when I make a GET request to my controller, the serialization of the entities fails, and it returns a XML (or JSON) full of errors:

api/houses (with Lazy Loading)

<Error> <Message>An error has occurred.</Message> <ExceptionMessage> The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'. </ExceptionMessage> <ExceptionType>System.InvalidOperationException</ExceptionType> <StackTrace/> <InnerException> <Message>An error has occurred.</Message> <ExceptionMessage> Type 'System.Data.Entity.DynamicProxies.House_49DC0BEAA9C67FACDA33CEE81852FA2D80C04F62C6838F92ACD2A490CECF86B5' with data contract name 'House_49DC0BEAA9C67FACDA33CEE81852FA2D80C04F62C6838F92ACD2A490CECF86B5:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies' is not expected. Consider using a DataContractResolver if you are using DataContractSerializer or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to the serializer. </ExceptionMessage> ... </Error>

If I "disable" Lazy Loading by removing the virtual keyword from the attributes, the entities are serialized correctly, but I no longer have access to the associated entities. If I make a GET request to fetch all the houses, I no longer have access to the House's Rooms:

api/houses (without Lazy Loading)

<ArrayOfHouse xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/REM.Models"> <House> <Address>Boaty McBoatface Street 123</Address> <ID>1</ID> <Rooms/> </House> </ArrayOfHouse>

I tried using Eager Loading to solve my problem by removing the virtual keywords and explicitly loading the Rooms in the GET method of the Houses controller like this:

HousesController.cs

public IQueryable<House> GetHouses() { return db.Houses.Include(r => r.Rooms); }

but it still failed to serialize the XML/JSON, showing me the exact same error message as when I tried to make a GET request with Lazy Loading.

I understand that all these problems may have something to do with circular dependency that is probably occurring between my two entities, but I have no idea how to solve it. So, to summarize all of this in one question:

Is there a way to make a request that will return all Houses with their respective Rooms, (without using auxiliary POCO (DTO))?

最满意答案

所以为了解决我的问题,我通过禁用EF代理来禁用延迟加载:

ApplicationDbContext.cs

public ApplicationDbContext() : base("name=ApplicationDbContext") { Configuration.ProxyCreationEnabled = false; }

我急切地在Houses控制器中加载了我的GET方法中的Rooms:

HousesController.cs

public IQueryable<House> GetHouses() { return db.Houses.Include(r => r.Rooms); }

它返回了我想要的XML:

<ArrayOfHouse xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/Test.Models"> <House> <Address>Boaty McBoatface Street 123</Address> <ID>1</ID> <Rooms> <Room> <ID>1</ID> <Name>Room</Name> </Room> <Room> <ID>2</ID> <Name>Kitchen</Name> </Room> </Rooms> </House> </ArrayOfHouse>

更新:

我找到了另一个实现我最初目标的解决方案。 您可以从属性中删除虚拟关键字,而不是禁用EF代理,然后您只需在GET方法中明确包含所需的实体,如下所示:

House.cs

public class House { public int ID { get; set; } public string Address { get; set; } public ICollection<Room> Rooms { get; set; } public House() { Rooms = new List<Room>(); } }

Room.cs

public class Room { public int ID { get; set; } public string Name { get; set; } }

按照这种方法,我从Room中删除了导航属性,因为这加剧了序列化问题,因为它导致了两个实体之间的循环依赖。

HouseController.cs

public IQueryable<House> GetHouses() { return db.Houses.Include(r => r.Rooms); }

So to solve my problem I disabled lazy loading by disabling EF proxies:

ApplicationDbContext.cs

public ApplicationDbContext() : base("name=ApplicationDbContext") { Configuration.ProxyCreationEnabled = false; }

And I eagerly loaded the Rooms in my GET method in the Houses controller:

HousesController.cs

public IQueryable<House> GetHouses() { return db.Houses.Include(r => r.Rooms); }

Which returned the XML that I wanted:

<ArrayOfHouse xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/Test.Models"> <House> <Address>Boaty McBoatface Street 123</Address> <ID>1</ID> <Rooms> <Room> <ID>1</ID> <Name>Room</Name> </Room> <Room> <ID>2</ID> <Name>Kitchen</Name> </Room> </Rooms> </House> </ArrayOfHouse>

Update:

I have found another solution that achieves my initial goal. Instead of disabling EF proxies you can remove the virtual keyword from your properties and then you only have to explicitly include the Entities that you want in the GET method, like this:

House.cs

public class House { public int ID { get; set; } public string Address { get; set; } public ICollection<Room> Rooms { get; set; } public House() { Rooms = new List<Room>(); } }

Room.cs

public class Room { public int ID { get; set; } public string Name { get; set; } }

Following this approach, I have removed the navigation property from Room because that was aggravating the serialization issue since it was causing a circular dependency between the two entities.

HouseController.cs

public IQueryable<House> GetHouses() { return db.Houses.Include(r => r.Rooms); }

更多推荐

本文发布于:2023-08-03 12:24:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1389297.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:序列   化与   实体   关系   Framework

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!