EF Core中SQL Server自引用多对多实体如何移除Materials列表?
解决步骤:移除Materials列表并适配DTO
1. 移除ProductEntity中的Materials列表并调整EF配置
直接从ProductEntity中删除Materials属性,修改后的实体类如下:
public class ProductEntity { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } = 0; [Required] public string Name { get; set; } [Required] public double PriceEuro { get; set; } public virtual List<ProductMaterialsJoin> ProductMaterials { get; set; } = new(); } public class ProductMaterialsJoin { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } = 0; [ForeignKey("ProductId")] public int ProductId { get; set; } [Required] public ProductEntity ProductEntity { get; set; } [ForeignKey("MaterialId")] public int MaterialId { get; set; } [Required] public ProductEntity MaterialEntity { get; set; } [Required] public int Amount { get; set; } }
接下来调整Fluent API配置,原来的多对多配置依赖Materials导航属性,现在改成直接配置实体与连接表的一对多/多对一关系:
protected override void OnModelCreating(ModelBuilder modelBuilder) { // 配置产品到关联记录的一对多关系 modelBuilder.Entity<ProductEntity>() .HasMany(p => p.ProductMaterials) .WithOne(pm => pm.ProductEntity) .HasForeignKey(pm => pm.ProductId) .OnDelete(DeleteBehavior.Cascade); // 按需选择删除行为 // 配置关联记录到原料产品的多对一关系 modelBuilder.Entity<ProductMaterialsJoin>() .HasOne(pm => pm.MaterialEntity) .WithMany() // 原料产品无需反向导航,用空重载即可 .HasForeignKey(pm => pm.MaterialId) .OnDelete(DeleteBehavior.Restrict); // 避免循环删除,按需调整 }
配置完成后,你可以通过ProductEntity.ProductMaterials访问该产品的所有原料关联记录,再通过MaterialEntity获取具体原料,Amount就是对应所需数量。
2. 实体与DTO的匹配映射
你的ProductDto用Dictionary<Product, int>存储原料和数量(这里的Product建议替换为对应的ProductDto类),可以按以下方式完成映射:
- 查询产品时包含关联的原料数据:
var productEntity = await _dbContext.Products .Include(p => p.ProductMaterials) .ThenInclude(pm => pm.MaterialEntity) .FirstOrDefaultAsync(p => p.Id == productId);
- 将实体转换为DTO时,把
ProductMaterials转换为字典:
var productDto = new ProductDto { Id = productEntity.Id, Name = productEntity.Name, PriceEuro = productEntity.PriceEuro, Materials = productEntity.ProductMaterials.ToDictionary( pm => new ProductDto { Id = pm.MaterialEntity.Id, Name = pm.MaterialEntity.Name, PriceEuro = pm.MaterialEntity.PriceEuro, Materials = new Dictionary<ProductDto, int>() // 基础原料此处为空 }, pm => pm.Amount ) };
如果需要处理多层嵌套原料(比如产品A包含原料B,原料B又包含原料C),可以编写递归映射方法完成深层转换。
内容的提问来源于stack exchange,提问作者dohlenaugur
相关产品推荐
相关产品推荐

