包含属性,但排除该属性的属性之一 [英] Include property but exclude one of that property's properties

查看:96
本文介绍了包含属性,但排除该属性的属性之一的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Let's say I have a method like this in one of my controllers:

[Route("api/Products")]
public IQueryable<Product> GetProducts() {
    return db.Products
             .Include(p => p.Category);
}

使用此方法,我可以从数据库中获取产品并包括其Category属性.

Using this I can get a product from the database and include its Category property.

在我的CategoryController中,我有以下方法:

In my CategoryControllerI have this method:

[Route("api/Categories")]
public IQueryable<Category> GetCategories() {
    return db.Categories
             .Include(c => c.Parent)
             .Include(c => c.Products)
             .Include(c => c.SubCategories);
}

当我将GET请求发送到CategoryController时,它可以按预期工作,我得到了类别,其父级,其产品及其子类别.但是,当我将GET请求发送到ProductController时,我不想将所有产品都包括在所请求产品的类别中,我只需要有关该类别的基本信息.

When I send a GET request to the CategoryController this works as intended, I get the category, its parent, its products and its sub-categories. But when I send a GET request to the ProductController I don't want to include all the products in the category of the requested product, I just need the basic information about that category.

那么,如何使GetProducts()返回数据库中的产品,包括每个产品的Category属性,但不包括该类别的Products列表属性,仍然保留id,title等其他属性?

So, how can I make GetProducts() return the products in the database, including the Category property of each product, but excluding the Products list property of the category, still keeping the other properties like id, title and so on?

谢谢.

推荐答案

如评论中所述,第一步是禁用延迟加载.您可以通过从集合属性中删除virtual修饰符(这是永久性的)或通过为每个上下文实例禁用它(这是临时性的)来做到这一点:

As said in the comments, the first step is to disable lazy loading. You can either do that by removing the virtual modifier from the collection properties, which is permanent, or by disabling it per context instance, which is temporary:

context.Configuration.ProxyCreationEnabled = false;

(禁用代理创建也会禁用延迟加载,但会使生成的对象更轻量).

(disabling proxy creation also disables lazy loading, but keeps the generated objects more light-weight).

在断开连接的场景中,例如Web AIP2(如您最初标记的问题),由于这种serializer-lazy-loading级联,人们通常更喜欢默认情况下禁用延迟加载.

In disconnected scenarios, like Web AIP2 (as you originally tagged the question), people often prefer to disable lazy loading by default, because of this serializer-lazy-loading cascade.

但是,您不能阻止Entity Framework执行关系修复 .加载Product会将其附加到上下文. Include()-将其类别附加那些到上下文中,并且EF会使用附加的产品填充其Products集合,无论您是否喜欢.

However, you can't stop Entity Framework from executing relationship fixup. Loading a Productattaches it to the context. Include()-ing its categories attaches those to the context and EF populates their Products collections with the attached product, whether you like it or not.

您可以通过使用AsNoTracking获取产品(这样可以防止实体被附着,即进行更改跟踪)来某种程度地减少这种影响:

You can somewhat reduce this effect by fetching the products with AsNoTracking (which prevents entities to get attached, i.e. change-tracked):

return db.Products.AsNoTracking()
         .Include(p => p.Category);

现在类别将仅用其类别的Product填充其Products.

Now categories will only have their Products filled with the Product of which they are the category.

顺便说一句,在断开连接的情况下,也最好使用AsNoTracking.无论如何,这些实体永远不会被同一上下文实例保存,从而提高了性能.

By the way, in disconnected scenarios, also using AsNoTracking is preferred. The entities won't ever be saved by the same context instance anyway and it increases performance.

  • 返回DTO,而不是实体类型

通过使用DTO对象,您可以完全控制将被序列化的对象图.延迟加载不会让您感到惊讶.但是,是的,所需的DTO类的数量可能是压倒性的.

By using DTO objects you take full control over the object graph that will be serialized. Lazy loading won't surprise you. But yeah, the amount of required DTO classes can be overwhelming.

  • 返回匿名类型.

这将引起我们的关注,因为我们永远都不应从方法中返回匿名类型,对吗?好吧,它们将动作方法保留为Json字符串,就像命名类型一样,而javascript客户端不知道区别.您可能会说,它只会使弱类型的javascript环境更近一步.唯一的事情是,命名的DTO类型用作数据契约(某种形式),匿名类型可以很容易地更改(也可以更改)并破坏客户端代码.但是我们总是对所有内容进行单元测试,对吗?嗯,在较小的开发团队中这是一个可行的选择.

This will raise some eyebrows because we should never return anonymous types from methods, right? Well, they leave an action method as a Json string, just as named types, and the javascript client doesn't know the distinction. You might say that it only brings the weakly typed javascript environment one step closer. The only thing is that a named DTO type serves as a data contract (of sorts) and anonymous types can be changed (too) easily and break client-side code. But we always unit-test everything, do we? Hmm, it's a viable option in smaller development teams.

  • 调整序列化器.

您可以告诉Json.Net序列化程序忽略引用循环.直接使用JsonConvert,看起来像这样:

You can tell the Json.Net serializer to ignore reference loops. Using JsonConvert directly, it looks like so:

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是参考循环.

In combination with AsNoTracking() this will serialize the categories with empty Products arrays ("Products": []), because Product - Category - Product is a reference loop.

在Web API中,有几种方法可以配置内置的Json.Net序列化器,您可能需要这样做

In Web API there are several ways to configure the built-in Json.Net serializer, you may want to do this per action method.

我个人更喜欢使用DTO.我喜欢控制住自己(也可以控制穿过电线的属性),而且我不特别喜欢依靠序列化程序为我解决自己忽略的事情.

Personally, I prefer using DTOs. I like to be in control (also over the properties that cross the wire) and I don't particularly like to rely on a serializer to solve for me what I neglected to do.

这篇关于包含属性,但排除该属性的属性之一的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆