EF Core多对多查询加入3个表
Posted
技术标签:
【中文标题】EF Core多对多查询加入3个表【英文标题】:EF Core Many to Many Querying to join 3 tables 【发布时间】:2021-12-27 19:33:54 【问题描述】:我有以下代码:
public class ProductTbl
public override int Id get; set;
public string ProductName get; set;
public List<ProductManufacturer> ProductManufacturer get; set; //M2M
public class Manufacturer_LKP
public override int Id get; set;
public string ManufacturerName get; set;
public List<ProductManufacturer> ProductManufacturer get; set; //M2M
public class ProductManufacturer
public ProductTbl Product get; set;
public int ProductID get; set;
public Manufacturer_LKP Manufacturer get; set;
public int ManufacturerID get; set;
public class SupplierTbl
public int SupplierID get; set;
public string SupplierName get; set;
public class ProductSuppliertbl
public int Id get; set;
public ProductTbl Product get; set;
public int ProductID get; set;
public SuppilerTbl Supplier get; set;
public int SupplierID get; set;
*我需要编写 Linq 查询来连接所有 3 个表(Product、Manufacture、ProductManufacturer),以便在一次 DB 行程中同时获得 ProductName 和 ManufatureName *当我执行以下操作时,我错过了 Manufacture 对象 (Manufacture=Null)
DbSet<ProductTbl>()
.Where(a => a.Id == 5)
.AsNoTracking()
.Include(a => a.ProductType)
.Include(a => a.ProductManufacturer)
以上 Linq 只是将 Product 表与 ProductManufacture 表联合起来,所以我无法获取“ManufactureName”
那么有什么方法可以在一次 DB 行程中加入 3 个表以在 ProductName 旁边获取 ManufactureName 吗?
【问题讨论】:
那么,最后需要什么?具有两个字段或整个对象图的 DTO?Include
不是JOIN,是加载相关数据的指令。
您不需要任何类型的 JOIN。 Include
不加入,它控制急切加载。 EF Core 根据实体之间的关系根据需要生成 JOIN。如果您的查询实际检索到相关的实体属性,即使没有Include
,EF 也会生成 JOIN
【参考方案1】:
在尝试加载相关数据时,投影是您的朋友。多对多的问题是你说一个产品有很多制造商,同时它有很多供应商
该产品需要对该产品的 ProductSuppliers 的引用,以便轻松管理许多供应商的要求。
var productData = context.Products
.Select(p => new
p.ProductName,
ManufacturerNames = p.ProductManufacturers.Select(pm => pm.Manufacturer.ManufacturerName).ToList(),
SupplierNames = x.ProductSuppliers.Select(ps => ps.Supplier.SupplierName).ToList()
).ToList();
这会为您提供一个产品列表,其中包含每个产品的相关制造商名称和供应商名称。使用该数据,您可以按照您认为合适的方式格式化输出。
如果你想要实体本身,那么缺少的位是ThenInclude
:
var products = context.Products
.Include(p => p.ProductManufacturers)
.ThenInclude(pm => pm.Manufacturer)
.Include(p => p.ProductSuppliers)
.ThenInclude(ps => ps.Supplier)
.AsNoTracking()
.ToList();
这将加载整个实体图。
如果您不想或不能将 ProductSuppliers 集合放入产品中,那么您可以完全从 ProductSupplier 构建查询,但这有点麻烦。
如果您使用的是 EF Core 5 并且您的加入实体(ProductManufacturer/ProductSupplier)只是对其各自实体的 FK 引用,那么您可以取消加入实体并让 EF 在幕后对其进行管理。产品将只包含一组制造商和一组供应商。这些仍然可以使用HasMany..WithMany
进行配置,但是在没有中间实体的情况下使查询更加清晰。
即
var productData = context.Products
.Select(p => new
p.ProductName,
ManufacturerNames = p.Manufacturers.Select(m => m.ManufacturerName).ToList(),
SupplierNames = x.Suppliers.Select(s => ps.SupplierName).ToList()
).ToList();
和
var products = context.Products
.Include(p => p.Manufacturers)
.Include(p => p.Suppliers)
.AsNoTracking()
.ToList();
...分别。仅当您要在连接实体中访问其他属性时,才需要中间连接实体。 (即 CreatedBy/At 等)
【讨论】:
【参考方案2】:试试这个
var list = context.ProductManufactures
.Select(i => new
ProductName = i.Product.ProductName,
ManufacturerName = i.Manufacturer.ManufacturerName,
SupplierNames = i.Product.ProductSuppliers.Select(s => s.SupplierName).ToList()
).ToList();
或者你也可以试试这个
var productData = context.Products
.Select(i => new
ProductName= i.ProductName,
ManufacturerNames = i.ProductManufacturers.Select(m => m.Manufacturer.ManufacturerName),
SupplierNames = i.ProductSuppliers.Select(s => s.Supplier.SupSupplierName)
).ToList();
但在此之前您必须修复一些导航属性
public class Product
public int Id get; set;
public string ProductName get; set;
public List<ProductManufacturer> ProductManufacturers get; set;
public List<ProductSupplier> ProductSuppliers get; set;
public class Supplier
public int SupplierID get; set;
public string SupplierName get; set;
public List<ProductSupplier> ProductSuppliers get; set;
public class ProductSupplier
public int Id get; set;
public Product Product get; set;
public int ProductID get; set;
public Supplier Supplier get; set;
public int SupplierID get; set;
public class Manufacturer_LKP
public int Id get; set;
public string ManufacturerName get; set;
public List<ProductManufacturer> ProductManufacturer get; set;
public class ProductManufacturer
public Product Product get; set;
public int ProductID get; set;
public Manufacturer_LKP Manufacturer get; set;
public int ManufacturerID get; set;
【讨论】:
请格式化您的代码,阅读起来很糟糕。 @Serge 知道了,但是如果我有另一个与产品表有多对多关系的表怎么办。即供应商_TBL,我需要在同一个数据库行程中的(产品名称和制造商名称)旁边附加供应商名称??感谢您的帮助:) 请也发布您的另一个表以及它与 3 个表的关系 公共类 SupplierTbl public int SupplierID get;放; 公共字符串供应商名称 获取;放; 公共类 ProductSupplierTbl 公共 int Id 获取;放; 公共 ProductTbl 产品 获取;放; 公共 int ProductID 获取;放; 公共 SuppilerTbl 供应商 获取;放; 公共 int 供应商 ID 获取;放; @Serge 主帖已更新为新实体“供应商”。现在我需要得到 (Product_Name , Manufacturer_Name, Supplier_Name) @Serge以上是关于EF Core多对多查询加入3个表的主要内容,如果未能解决你的问题,请参考以下文章