我正在使用 EF 5 和 ASP.NET Web API 从我的 Controller 返回 JSON。我的例子是宠物服务。对于这个问题,实体是 Client
、Pet
和 Veterinarian
。关系是:
Client => one-to-many => Pet => one-to-one => Veterinarian
并且,颠倒层次结构:
Veterinarian => one-to-many => Pet => one-to-one => Client
在我的 PetsController
中,GetPets
操作如下所示:
var pets= db.Pets
.Where(p => p.IsActive == true)
.Include(p => p.Client)
.Include(p => p.Veterinarian);
return Mapper.Map<IEnumerable<Pet>, IEnumerable<PetDTO>>(pets); // Using Automapper to map to a DTO
生成的 JSON 包含宠物,每个宠物对应一个客户,每个宠物对应一个 vert 并且每个 vert 对应一个宠物集合。
我理解为什么宠物集合会显示在 JSON 中,但它与 Controller 操作中的宠物列表不相关(至少现在不相关)。我正在寻找一种优雅的方式来删除宠物的集合。现在我正在使用感觉像是 hack 的东西:
var pets= db.Pets
.Where(p => p.IsActive == true)
.Include(p => p.Client)
.Include(p => p.Veterinarian);
foreach (Pet pet in pets) {
pet.Veterinarian.Pets = null; // Remove the Pets collection before serializing
}
return Mapper.Map<IEnumerable<Pet>, IEnumerable<PetDTO>>(pets); // Using Automapper to map
我已经用序列化程序和一些 IQuerable
方法(其中很多我不熟悉)尝试了一些事情,但无济于事。
最佳答案
您可以禁用延迟加载来修剪图形。但这仍然不能始终解决问题。如果你有双向关系(比如 pet <=> Veterinarian),使用 Include 获取关系的一侧也会自动构建另一侧。因此,在您查询之后,即使您没有在 Include
中明确询问,pet.Veterinarian.Pets
也不会为空。
使用 DTO 是我能想到的最佳方式。您可以完全控制对象图。
此外,OData 协议(protocol)已经通过 $select 和 $expand 定义了这种机制,并将控制权交给客户端以指定它需要的对象图的深度和广度。例如,对于您的场景,OData url 看起来像 ~/Pets?$expand=Client,Veterinarian
。您是否考虑过 OData 来满足您的需求?
如果您不想每次都创建 DTO,您可以使用匿名对象即时创建。例如,对于您的场景,您可以这样做,
db.Pets.Select(p => new
{
Id = p.ID,
.... other pet properties you want,
Veterinarian = new
{
ID = p.Veterinarian.ID
... other veterinarian properties you want
},
Client =
{
... client properties you need.
}
});
不过,这只是将映射移动到 select 子句中。
关于c# - EF、ASP.NET Web API 和 JSON.NET - 返回限制层次结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15684484/