Entity Framework core 2.1 多对多选择查询

Posted

技术标签:

【中文标题】Entity Framework core 2.1 多对多选择查询【英文标题】:Entity Framework core 2.1 Many To Many Select Query 【发布时间】:2019-06-12 10:04:49 【问题描述】:

如何使用 Linq 创建以下查询?

SELECT product.name, product.code, category.Name FROM product 
INNER JOIN productCategories ON product.ID = productCategories.productID 
INNER JOIN category ON productCategories.categoryID = category.ID 
WHERE productCategories.ID = idToFind

产品和类别类:

public class Product

    public Product()
    
        this.Categories = new HashSet<Category>();
        
    public int ID  get; set;     
    public string Code  get; set; 
    public string Name  get; set; 
    public virtual ICollection<Category> Categories  get; set; 



public class Category

    public Category()
    
        this.Products = new HashSet<Product>();
        this.Children = new HashSet<Category>();
    
    public int ID  get; set; 

    [StringLength(150)]
    public string Name  get; set; 
    public int? ParentID  get; set; 
    public virtual Category Parent  get; set; 

    public virtual ICollection<Category> Children  get; set; 
    public virtual ICollection<Product> Products  get; set; 

我尝试了几种不同的方法,如果我只需要一个表中的列,但无法从两个表中获取详细信息,即类别名称和产品名称,我可以获得结果。

编辑: 我现在添加了一个 JunctionClass

public class CategoryProduct

    public int CategoryID  get; set; 
    public Category Category  get; set; 

    public int ProductID  get; set; 
    public Product Product  get; set; 


并尝试过:

var results = _context.Product.Include(e => e.categoryProducts).ThenInclude(e => e.Category).Where(c=>c.categoryProducts.Category.ID==169).ToList();

但我仍然无法让它工作。 得到错误:

'ICollection<CategoryProduct>' does not contain a definition for 'Category' and no accessible extension method 'Category' accepting a first argument of type 'ICollection<CategoryProduct>' could be found 

【问题讨论】:

缺少您查询数据的代码。到目前为止,您自己尝试过什么?并向我们​​展示相关的 Dbcontext 代码。 你需要明确指定一个联结表。 我现在已经添加了一个联结表,但我仍然不能让它按需要工作。 【参考方案1】:

在 EF 核心中,您需要一个联结表来映射多对多关系。

public class ProductCategory

    public int Id  get; set; 
    public int ProductId  get; set; 
    public Product Product  get; set; 
    public int CategoryId  get; set; 
    public Category Category  get; set; 


public class Product

    ...
    public virtual ICollection<ProductCategory> ProductCategories  get; set; 


public class Category

    ...
    public virtual ICollection<ProductCategory> ProductCategories  get; set; 


// DbContext
public DbSet<ProductCategory> ProductCategories  get; set; 

public override OnModelCreating(ModelBuilder builder)

    builder.Entity<ProductCategory>()
           .HasOne(pc => pc.Product)
           .WithMany(p => p.ProductCategories);

    builder.Entity<ProductCategory>()
           .HasOne(pc => pc.Category)
           .WithMany(c => c.ProductCategories);


// Query
var result = await dbContext.ProductCategories
                     .Select(pc => new 
                         ProductName = pc.Product.Name, 
                         ProductCode = pc.Product.Code, 
                         CategoryName = pc.Category.Name 
                      )
                     .SingleOrDefaultAsync(pc => pc.Id == idToFind)

【讨论】:

谢谢,我已经添加了一个联结表,但仍然无法得到可以返回我需要的数据的东西。 有什么问题?我在这里复制了您的查询。如果您用英语陈述您的查询,我可能会查看 SQL 是否匹配。这部分对我来说是有问题的WHERE productCategories.ID = idToFind您正在直接查找连接表,这几乎从未发生过。您是否尝试按产品 ID 进行搜索? 我没有看到滚动条。我试图做 dbContext.Product,然后获取 categoryproducts,然后是类别。但是我不断收到语法错误。您的查询效果很好。 重要的是,在 EF Core 5.0 中你不再需要连接表:docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-5.0/…【参考方案2】:
//Mock SomeData
List<Product> products = new List<Product>();
List<Category> category = new List<Category>();
//Linq
var result = products.SelectMany(product => product.Categories.SelectMany(productCategory => category.Where(category => category.ID == productCategory.ID).Select(category => new  category.Name, ProductName = product.Name, product.Code )));

【讨论】:

当我尝试时:var result = _context.Product.SelectMany(product => product.categoryProducts.SelectMany(productCategory => _context.Category.Where(category => category.ID == 169)。 Select(category => new category.Name, ProductName = product.Description, product.Code )));我得到一个错误:必须是可约节点 请在您的答案中添加解释。【参考方案3】:

试试这个

var idToFind = 3;

var o = (from p in _products
         from c in p.Categories
         where c.ID == idToFind
         select new ProductName = p.Name, ProductCode = p.Code, CategoryName = c.Name).ToList();

【讨论】:

以上是关于Entity Framework core 2.1 多对多选择查询的主要内容,如果未能解决你的问题,请参考以下文章

Entity Framework core 2.1 多对多选择查询

使用 Entity Framework Core (2.1) 调用标量函数的最佳实践

Entity Framework Core 2.1 无法更新具有关系的实体

Entity Framework Core 2.1 - 拥有类型和嵌套值对象

Entity Framework Core快速开始

Entity Framework Core 快速开始