包含属性但排除该属性的属性之一
假设我的一个控制器中有这样的方法:
[Route("api/Products")] public IQueryable GetProducts() { return db.Products .Include(p => p.Category); }
使用这个我可以从数据库中获取产品并包含其Category属性。
在我的CategoryControllerI中有这个方法:
[Route("api/Categories")] public IQueryable GetCategories() { return db.Categories .Include(c => c.Parent) .Include(c => c.Products) .Include(c => c.SubCategories); }
当我向CategoryController发送GET请求时,它按预期工作,我得到类别,其父级,产品和子类别。 但是当我向ProductController发送GET请求时,我不想将所有产品都包含在所请求产品的类别中,我只需要有关该类别的基本信息。
那么,我如何让GetProducts()返回数据库中的产品,包括每个产品的Category属性,但不包括该类别的Products列表属性,仍然保留其他属性,如id,title等?
谢谢。
如评论中所述,第一步是禁用延迟加载 。 您可以通过从集合属性中删除virtual
修饰符(这是永久性的),或者通过每个上下文实例禁用virtual
修饰符来实现,这是临时的:
context.Configuration.ProxyCreationEnabled = false;
(禁用代理创建也会禁用延迟加载,但会使生成的对象保持更轻量级)。
在断开连接的场景中,例如Web AIP2(正如您最初标记问题的那样),人们通常更喜欢默认禁用延迟加载,因为此序列化器 – 延迟加载级联。
但是, 您无法阻止Entity Framework执行关系修复 。 加载Product
会将其附加到上下文中。 Include()
其类别附加到上下文中,并且EF使用附加产品填充其Products
集合,无论您是否喜欢。
您可以通过使用AsNoTracking
获取产品来减少此影响(这会阻止实体附加,即更改跟踪):
return db.Products.AsNoTracking() .Include(p => p.Category);
现在类别只会让他们的Products
填充他们所属的Products
。
顺便说一句,在断开连接的场景中,也首选使用AsNoTracking
。 无论如何,实体都不会被相同的上下文实例保存,从而提高了性能。
解决方案
- 返回DTO,而不是实体类型
通过使用DTO对象,您可以完全控制将要序列化的对象图。 延迟加载不会让你感到惊讶。 但是,所需的DTO课程数量可能是压倒性的。
- 返回匿名类型。
这会引起一些人的注意,因为我们永远不应该从方法中返回匿名类型,对吧? 好吧,他们将动作方法保留为Json字符串,就像命名类型一样,并且javascript客户端不知道区别。 你可能会说它只会使弱类型的javascript环境更近一步。 唯一的事情是命名的DTO类型用作数据契约(各种类型),匿名类型可以(太)轻松地更改并破坏客户端代码。 但我们总是对所有东西进行unit testing,对吗? 嗯,这是小型开发团队的可行选择。
- 调整序列化器。
您可以告诉Json.Net序列化程序忽略引用循环。 直接使用JsonConvert
,它看起来像这样:
var products = db.Products.AsNoTracking().Include(p => p.Category); var setting = new JsonSerializerSettings { Formatting = Newtonsoft.Json.Formatting.Indented, // Just for humans ReferenceLoopHandling = ReferenceLoopHandling.Ignore }; var json = JsonConvert.SerializeObject(products, setting);
与AsNoTracking()
结合使用时,这将使用空的Products
数组( "Products": []
)序列化类别,因为Product - Category - Product
是一个参考循环。
在Web API中,有几种方法可以配置内置的Json.Net序列化程序,您可能希望按操作方法执行此操作 。
就个人而言,我更喜欢使用DTO。 我喜欢控制(也是通过电线的属性)我并不特别喜欢依靠序列化器为我解决我忽略的事情。
- WebApi 2 POST使用单个字符串参数而不是wokring
- ApiController扩展方法 – 无法访问ResponseMessage
- 自定义MultipartFormDataStreamProvider上传后,通过WebApi从SQL下载大文件
- 使用JsonProperty对JSON进行Model属性绑定
- WebAPI 2.0 Post未反序列化List 属性
- Web API Gzip未被应用
- 获取连接到C#.NET WebAPI应用程序的客户端的IP地址
- 使用Web API 2进行Autofac – 无参数构造函数错误
- Web Api 2 – 如何从HTTPGET返回映像(来自Azure存储的MemoryStream)而不保存到磁盘?