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

EF Core结合DDD实现数据库复合主键配置问题

EF Core配置DDD实体映射数据库复合主键方案

1. 定义DDD值对象ChecklistId

针对数据库的复合主键字段,设计不可变的值对象,保证值相等语义(推荐用record简化实现,也可手动实现IEquatable):

用Record实现(.NET 8推荐)

public record ChecklistId(
    int InspectionId,
    string QuestionGroup,
    string Question,
    string Answer);

用Class手动实现(如需自定义校验逻辑)

public class ChecklistId : IEquatable<ChecklistId>
{
    public int InspectionId { get; }
    public string QuestionGroup { get; }
    public string Question { get; }
    public string Answer { get; }

    private ChecklistId(int inspectionId, string questionGroup, string question, string answer)
    {
        InspectionId = inspectionId;
        QuestionGroup = questionGroup ?? throw new ArgumentNullException(nameof(questionGroup));
        Question = question ?? throw new ArgumentNullException(nameof(question));
        Answer = answer ?? throw new ArgumentNullException(nameof(answer));
    }

    public static ChecklistId Create(int inspectionId, string questionGroup, string question, string answer)
    {
        // 可添加业务校验:比如InspectionId不能为负,字符串非空等
        return new ChecklistId(inspectionId, questionGroup, question, answer);
    }

    public bool Equals(ChecklistId other)
    {
        if (other is null) return false;
        return InspectionId == other.InspectionId
               && string.Equals(QuestionGroup, other.QuestionGroup, StringComparison.Ordinal)
               && string.Equals(Question, other.Question, StringComparison.Ordinal)
               && string.Equals(Answer, other.Answer, StringComparison.Ordinal);
    }

    public override bool Equals(object obj) => Equals(obj as ChecklistId);

    public override int GetHashCode() => HashCode.Combine(InspectionId, QuestionGroup, Question, Answer);
}

2. 定义Checklist实体

实体以ChecklistId作为唯一标识,封装业务属性和行为:

public class Checklist
{
    public ChecklistId Id { get; private set; }
    public DateTime CreatedAt { get; private set; }
    public string Inspector { get; private set; }

    // EF Core需要的无参构造(设为私有避免外部直接调用)
    private Checklist() { }

    // 业务构造函数,保证实体创建时的合法性
    public Checklist(ChecklistId id, DateTime createdAt, string inspector)
    {
        Id = id ?? throw new ArgumentNullException(nameof(id));
        CreatedAt = createdAt;
        Inspector = inspector ?? throw new ArgumentNullException(nameof(inspector));
    }

    // 业务方法示例
    public void UpdateInspector(string newInspector)
    {
        Inspector = newInspector ?? throw new ArgumentNullException(nameof(newInspector));
    }
}

3. EF Core Fluent API配置

在DbContext中通过Fluent API完成实体与数据库表的映射,重点是拆分值对象为复合主键列:

public class AppDbContext : DbContext
{
    public DbSet<Checklist> Checklists { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("Your_Connection_String", opt =>
        {
            // 适配SQL Server 2008的兼容级别
            opt.UseCompatibilityLevel(100);
            // 可选:配置重试逻辑
            opt.EnableRetryOnFailure();
        });
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Checklist>(entity =>
        {
            // 将值对象的四个属性设为复合主键
            entity.HasKey(c => new 
            { 
                c.Id.InspectionId, 
                c.Id.QuestionGroup, 
                c.Id.Question, 
                c.Id.Answer 
            });

            // 映射值对象属性到数据库列(可指定列名、长度等)
            entity.Property(c => c.Id.InspectionId)
                  .HasColumnName("InspectionId")
                  .IsRequired();

            entity.Property(c => c.Id.QuestionGroup)
                  .HasColumnName("QuestionGroup")
                  .HasMaxLength(100)
                  .IsRequired();

            entity.Property(c => c.Id.Question)
                  .HasColumnName("Question")
                  .HasMaxLength(200)
                  .IsRequired();

            entity.Property(c => c.Id.Answer)
                  .HasColumnName("Answer")
                  .HasMaxLength(500)
                  .IsRequired();

            // 映射其他业务属性
            entity.Property(c => c.CreatedAt)
                  .HasColumnName("CreatedAt")
                  .IsRequired();

            entity.Property(c => c.Inspector)
                  .HasColumnName("Inspector")
                  .HasMaxLength(50)
                  .IsRequired();

            // 指定数据库表名(若与实体名不一致)
            entity.ToTable("Checklist");
        });
    }
}

4. 使用注意事项

  • 查询实体:直接传入ChecklistId实例即可,EF Core会自动解析为复合条件:
var targetId = ChecklistId.Create(1, "Safety", "Fire Extinguisher", "Pass");
var checklist = await dbContext.Checklists.FirstOrDefaultAsync(c => c.Id == targetId);
  • 添加实体:通过业务构造函数创建合法实体后再入库:
var newChecklist = new Checklist(
    ChecklistId.Create(2, "Quality", "Material Check", "Conform"),
    DateTime.Now,
    "John Doe");
dbContext.Checklists.Add(newChecklist);
await dbContext.SaveChangesAsync();
  • SQL Server 2008兼容:避免使用2008不支持的特性(如JSON列、SEQUENCE),确保连接字符串适配旧版本Provider。

内容的提问来源于stack exchange,提问作者M.M

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 11:03:25