You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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类),可以按以下方式完成映射:

  1. 查询产品时包含关联的原料数据:
var productEntity = await _dbContext.Products
    .Include(p => p.ProductMaterials)
    .ThenInclude(pm => pm.MaterialEntity)
    .FirstOrDefaultAsync(p => p.Id == productId);
  1. 将实体转换为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 10:17:26