【问题标题】:Entity Framework - filtering and retrieving child entities on child entity condition实体框架 - 在子实体条件下过滤和检索子实体
【发布时间】:2020-11-09 02:36:32
【问题描述】:

我的问题如下:我有一个Product 实体,看起来像这样:

public int Id { get; set; }
public string Title { get; set; }
public decimal Price { get; set; }
public string Excerpt { get; set; }
public string Description { get; set; }
public virtual Category Category { get; set; }
public DateTime Published { get; set; }
public string[] Tags { get; set; }
public int PublisherId { get; set; }
public virtual User Publisher { get; set; }
public virtual ICollection<MyImage> Images { get; set; }

现在这个Product 实体可以有许多Images(作为子实体),如下所示:

public int Id { get; set; }
public string Description { get; set; }
public DateTime DateAdded { get; set; }
public bool IsMain { get; set; }
public byte[] Image { get; set; }
public virtual Product Product { get; set; }
public int ProductId { get; set; }

所以,我有一个控制器路由,我想在其中检索所有产品,并且只检索那些作为主要产品图像的图像(大多数情况下,它只是一个图像,但我仍然更喜欢返回它们的列表)。

目前,我正在尝试做的事情不起作用:

public async Task<PagedList<Product>> GetProducts(UserParams userParams)
{
     var productsFromRepo = context.Products
         .Select(p => new {
             Product = p,
             Images = p.Images.Where(i => i.IsMain)
         })
         .OrderByDescending(b => b.Product.Published);

     var productsToReturn = productsFromRepo.Select(i => i.Product).AsQueryable();
     return await PagedList<Product>.CreateAsync(productsToReturn, userParams.PageNumber, userParams.PageSize);
}

我尝试获取所有产品及其主要图片。并返回带有主图像的产品,而不是所有图像。如您所见,我返回了一个PagedList 对象,我需要将IQueryable 作为CreateAsync 方法的第一个参数传递。

问题是,我设法对我的匿名投影对象 (productsFromRepo) 进行了过滤。但我不知道如何将该匿名对象作为带有过滤图像列表的产品对象返回。

它总是返回所有图像,而不是按我的需要过滤。

在这个问题中,我必须有我最后投影的对象,在这种情况下,productsToReturn 是一个IQueryable 对象。

在我的项目中,我使用延迟加载。所以默认情况下所有子实体都是惰性加载的。

所以基本上,我得到的现在是:

[
    {
        "id": 2,
        "title": "My First Product",
        "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
        "category": "Uncategorized",
        "price": 15.0,
        "excerpt": "Lorem ipsum",
        "tags": [
            "Tag1",
            "Tag2"
        ],
        "images": [
            {
                "id": 1,
                "description": "test",
                "isMain": true,
                "dateAdded": "2020-07-15T22:40:09.285481",
                "image":"/9j/...."
            },
            {
                "id": 2,
                "description": "test1",
                "isMain": false,
                "dateAdded": "2020-07-15T23:15:44.74166",
                "image":"/9j/...."
            },
            {
                "id": 3,
                "description": "test1",
                "isMain": false,
                "dateAdded": "2020-07-15T23:27:39.636685",
                "image":"/9j/...."
            }
        ],
        "published": "2020-07-15T22:39:27.89482",
        "publisher": {
            "id": 1,
            "name": null,
            "lastName": null,
            "email": "testemail@gmail.com"
        }
    }
]

而我需要的是:

[
    {
        "id": 2,
        "title": "My First Product",
        "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
        "category": "Uncategorized",
        "price": 15.0,
        "excerpt": "Lorem ipsum",
        "tags": [
            "Tag1",
            "Tag2"
        ],
        "images": [
            {
                "id": 1,
                "description": "test",
                "isMain": true,
                "dateAdded": "2020-07-15T22:40:09.285481",
                "image":"/9j/...."
            },
        ],
        "published": "2020-07-15T22:39:27.89482",
        "publisher": {
            "id": 1,
            "name": null,
            "lastName": null,
            "email": "testemail@gmail.com"
        }
    }
]

提前致谢

【问题讨论】:

  • 实体反映数据状态,并且仅反映数据状态。如果您想要为您的视图过滤结果,这是一个单独的问题。 不要将实体发送到视图,将 ViewModel 发送到视图。 ViewModel 将表示您的视图需要的数据,并且仅表示您的视图需要的数据,以您的视图期望的方式。如果服务器代码草率,实体会暴露太多关于您的域模型的信息,并让您容易遇到意外的性能问题和篡改。
  • @StevePy 这不是您看到的我的控制器方法。这是存储库方法。我不是返回普通实体,而是返回一个 DTO,在那里我选择了该控制器返回的必要数据。感谢您的关注,但问题不完全是这样。
  • var productsToReturn = productsFromRepo.Select(i =&gt; i.Product) 反映了一个产品实体。要返回 DTO,您应该使用 Select 使用产品和“主”图像投影到 DTO。 IE。 productsFromRepo.Select(i =&gt; new ProductDTO { ProductId = i.Product.ProductId, /* etc */ Images = i.Images.Select(x =&gt; new ImageDTO { /* translate desired image properties to DTO */ }).ToList() }) 使用产品的详细信息编写产品 DTO,并根据过滤结果填充图像,而不是返回产品实体。

标签: c# asp.net .net entity-framework .net-core


【解决方案1】:

不要选择产品,而是选择图像:

public async Task<PagedList<Product>> GetProducts(UserParams userParams)
{
     var productsFromRepo = context.Images
         .Where(i => i.IsMain)
         .Select(i => new Product {
             Id = i.Product.Id,
             Title = i.Product.Title,
             ...
             Images = new List<Image>{ i }
         })
         .OrderByDescending(b => b.Published)
         .AsQuerable();

     return await PagedList<Product>.CreateAsync(productsFromRepo, userParams.PageNumber, userParams.PageSize);
}

【讨论】:

  • 这个解决方案的问题是,如果我的产品根本没有图片,它就不会出现在列表中。因此,我需要所有有或没有主图像的产品,只有当它们有一个或多个图像时,才返回主图像。谢谢你的回答,差不多就是我需要的了。
  • 这是一个很好的观点。您是否考虑过而不是在 Image 上使用 IsMain 属性,而是在 Product 中有一个外键,它指向与图像集合直接分离的主图像?然后你可以只在主图像上选择 - 如果有的话 - 而不是加载集合。
【解决方案2】:

好吧,我认为匿名对象没有帮助。您可以在从数据库中检索产品图片后对其进行过滤,或者如果您想阻止 EF 从数据库中获取产品图片,请使用 查询过滤器

查看此documentation 以获得清晰的图片。

想法是在图片实体的fluent api配置中包含查询过滤器:

builder.HasQueryFilter(p => p.IsMain);

这将阻止 EF 检索未设置为主要的图片,默认情况下在所有情况下。如果您希望 EF 检索所有图片(即在图片索引中),您必须使用

.IgnoreQueryFilters()

在您的查询中。

附:我没有包含完整的代码 sn-ps,如果对您没有意义,请让我演示完整的代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多