嵌套/分层集合的 DTO Linq 投影

本文关键字:DTO Linq 投影 集合 分层 嵌套 | 更新日期: 2023-09-27 18:36:48

我有一个UserProduct实体,定义如下:

public class User {
    Guid Id { get; set; }
    Guid ParentId { get; set; }       
    ICollection<Product> PermittedProducts { get; set; }
    ICollection<User> Children { get; set; }
}
public class Product {
    int Id { get; set; }
    string Name { get; set; }
    ICollection<User> PermittedUsers { get; set; }
}

从概念上讲,Product具有一组PermittedUsers - 即可以购买该产品的用户。此外,每个User都有一个 PermittedProducts 的集合,以及一个子用户的集合,这些用户也有自己的PermittedProducts集合。

我需要通过存储库运行查询以返回产品列表。 存储库方法和 DTO 定义为:

  public ICollection<ProductListDto> GetProductsForUser(Guid userId) {
       // Linq query here
  }
  public class ProductListDto {
      int Id { get; set; }
      string Name { get; set; }
      ICollection<User> Users { get; set; }
  }

存储库方法需要获取 Guid userId并检索该用户的PermittedProducts用户子项的PermittedProducts

例如,如果产品可供用户及其两个子级使用,则 ProductListDto 将在其用户集合中具有所有三个用户。

再举一个例子,如果产品对用户不可用,但对他的子项可用,那么也需要返回。

ProductUser都可以作为聚合根使用,因此我可以使用ProductRepositoryUserRepository通过EntityFramework的DbSet进行查询。

目前我的存储库方法在UserRepository中(但如果查询更简单,则可以移动到ProductRepository),如下所示:

 public ICollection<ProductListDto> GetProductsForUser(Guid userId) {
       // Linq query here - Set is the EF DbSet<User> 
       var products = from u in 
           Set.Where(x => x.Id == userId) //.... NOT SURE ABOUT THE REST!
  }

我的问题是我无法弄清楚如何编写 Linq 查询来实现我需要做的事情!

编辑

到目前为止,答案还没有解决如何实现对ProductListDto的投影

嵌套/分层集合的 DTO Linq 投影

我的方法就是简单地从父用户 ID 构建一个 Id 列表,这样它将包含父用户 ID 及其所有 ChildId。然后,我们可以从允许用户包含这些 ID 之一的产品中进行选择。这是您可以从中获取产品列表的地方。

        var childIds = DbContext.Users.Where(x => x.Id == userId).SelectMany(y => y.Children.Select(z => z.Id)).ToList();
        childIds.Add(userId);
        var products = DbContext.Products.Where(x => x.Users.SelectMany(y => childIds.Contains(y.Id))).ToList();

试试这个

userRepository.Where(u => u.Id == userId && u.ParentId == userId)
            .SelectMany(u => u.PermittedProducts)
            .GroupBy(p => p.Id)
            .Select(u => u.First());

线路解释 - 1)检索目标用户及其子用户 - 2)从用户集合中选择我们在第一行获得的所有产品 - 3- 4) 删除重复项。

请注意,此类 linq 可以转换为繁重的 sql 查询,这会降低性能。也许最好在行(1、2 或 3)之后调用 ToList。也可以编写自己的SQL查询,将它们存储在sql服务器中,然后按名称从代码调用它们。