包含属性但排除该属性的属性之一

假设我的一个控制器中有这样的方法:

[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。 我喜欢控制(也是通过电线的属性)我并不特别喜欢依靠序列化器为我解决我忽略的事情。