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

EF Core单SQL表映射一对多C#实体问题求助

解决EF Core单表映射为一对多实体的方案

前提假设

假设你的SQL表结构类似如下(可根据实际字段调整):

CREATE TABLE ModelItemData (
    Model NVARCHAR(50) NOT NULL,
    Version NVARCHAR(20) NOT NULL,
    ItemId INT IDENTITY(1,1) NOT NULL,
    ItemName NVARCHAR(100) NOT NULL,
    ItemValue NVARCHAR(MAX) NULL,
    PRIMARY KEY (Model, Version, ItemId)
)

1. 定义实体类

将单表拆分为一对多的两个实体,父实体对应Model+Version的分组,子实体对应单条明细:

// 父实体:对应Model+Version的分组
public class ModelVersionControl
{
    // 复合主键:唯一标识一组版本
    public string Model { get; set; }
    public string Version { get; set; }

    // 导航属性:关联该版本下的所有明细Item
    public ICollection<Item> Items { get; set; } = new List<Item>();
}

// 子实体:对应表中的每条明细记录
public class Item
{
    // 外键:关联父实体的复合主键
    public string Model { get; set; }
    public string Version { get; set; }

    // 自身唯一标识(根据表结构调整,可设为自增ID)
    public int ItemId { get; set; }

    // 业务字段
    public string ItemName { get; set; }
    public string ItemValue { get; set; }

    // 反向导航属性:关联父实体
    public ModelVersionControl ModelVersion { get; set; }
}

2. 配置DbContext映射

通过Fluent API显式配置实体与表的映射、主键及一对多关系:

public class MyDbContext : DbContext
{
    public DbSet<ModelVersionControl> ModelVersions { get; set; }
    public DbSet<Item> Items { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        // 替换为你的数据库连接字符串
        optionsBuilder.UseSqlServer("YourConnectionString");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // 配置父实体映射
        modelBuilder.Entity<ModelVersionControl>(entity =>
        {
            // 设置复合主键
            entity.HasKey(m => new { m.Model, m.Version });
            // 指定映射到目标SQL表
            entity.ToTable("ModelItemData");
            // 配置一对多关系:一个分组对应多个明细
            entity.HasMany(m => m.Items)
                  .WithOne(i => i.ModelVersion)
                  .HasForeignKey(i => new { i.Model, i.Version })
                  .OnDelete(DeleteBehavior.Cascade);
        });

        // 配置子实体映射
        modelBuilder.Entity<Item>(entity =>
        {
            // 设置子实体主键(与SQL表主键一致)
            entity.HasKey(i => new { i.Model, i.Version, i.ItemId });
            // 同样映射到目标SQL表
            entity.ToTable("ModelItemData");
        });
    }
}

3. 无Group By的查询方式

直接通过导航属性加载关联数据,无需手动分组:

using (var context = new MyDbContext())
{
    // 加载所有版本分组及对应的明细
    var allVersionGroups = context.ModelVersions
                                  .Include(m => m.Items)
                                  .ToList();

    // 查询指定Model和Version的分组数据
    var specificGroup = context.ModelVersions
                               .Include(m => m.Items)
                               .FirstOrDefault(m => m.Model == "OrderModel" && m.Version == "v2.1");
}

常见问题排查

  • 确保父实体的复合主键与子实体的外键字段类型、名称完全匹配
  • 必须显式配置两个实体映射到同一个SQL表,否则EF会默认生成两张表
  • 若SQL表主键不是复合键,可将子实体主键设为单独的ItemId,但外键仍需关联Model+Version

内容的提问来源于stack exchange,提问作者Emad Ali

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 19:05:24