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

EF Core 7:复合主键映射至强类型ID对象的实现方案

解决方案:EF Core 映射 Oracle 复合主键到强类型 ID(DDD 风格)

1. 修正强类型 ID 的值对象实现(符合 DDD 规范)

首先需要让强类型 ID 成为不可变的值对象,实现相等性判断(EF Core 依赖此处理主键/外键的比较逻辑):

public sealed class ExampleIdentityKey : IEquatable<ExampleIdentityKey>
{
    public string Id1 { get; }
    public string Id2 { get; }
    public string Id3 { get; }
    public string Id4 { get; }

    // EF Core 所需的无参私有构造
    private ExampleIdentityKey() { }

    // 公开构造函数,确保 ID 字段不可变
    public ExampleIdentityKey(string id1, string id2, string id3, string id4)
    {
        Id1 = id1 ?? throw new ArgumentNullException(nameof(id1));
        Id2 = id2 ?? throw new ArgumentNullException(nameof(id2));
        Id3 = id3 ?? throw new ArgumentNullException(nameof(id3));
        Id4 = id4 ?? throw new ArgumentNullException(nameof(id4));
    }

    // 实现值对象相等性判断
    public bool Equals(ExampleIdentityKey? other)
    {
        if (other is null) return false;
        return Id1 == other.Id1 && Id2 == other.Id2 && Id3 == other.Id3 && Id4 == other.Id4;
    }

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

    public override int GetHashCode() => HashCode.Combine(Id1, Id2, Id3, Id4);

    public static bool operator ==(ExampleIdentityKey? left, ExampleIdentityKey? right) => Equals(left, right);
    public static bool operator !=(ExampleIdentityKey? left, ExampleIdentityKey? right) => !Equals(left, right);
}

2. 通用复合主键映射扩展(避免重复配置)

由于所有表都使用相同的复合主键结构,创建通用扩展方法统一处理映射逻辑:

public static class EntityTypeBuilderExtensions
{
    public static EntityTypeBuilder<TEntity> ConfigureCompositeId<TEntity, TId>(
        this EntityTypeBuilder<TEntity> builder,
        Expression<Func<TEntity, TId>> idExpression,
        string tableName)
        where TEntity : class
        where TId : class
    {
        builder.ToTable(tableName);

        // 将强类型 ID 配置为「拥有类型」,EF Core 会自动拆分其属性到数据库列
        var ownedIdBuilder = builder.OwnsOne(idExpression, idBuilder =>
        {
            idBuilder.Property(p => p.Id1).HasColumnName("ID1").IsRequired();
            idBuilder.Property(p => p.Id2).HasColumnName("ID2").IsRequired();
            idBuilder.Property(p => p.Id3).HasColumnName("ID3").IsRequired();
            idBuilder.Property(p => p.Id4).HasColumnName("ID4").IsRequired();
        });

        // 将拆分后的四个字段设置为复合主键
        builder.HasKey(
            ownedIdBuilder.OwnedType.Property(p => p.Id1).Metadata.Name,
            ownedIdBuilder.OwnedType.Property(p => p.Id2).Metadata.Name,
            ownedIdBuilder.OwnedType.Property(p => p.Id3).Metadata.Name,
            ownedIdBuilder.OwnedType.Property(p => p.Id4).Metadata.Name);

        return builder;
    }
}

3. 单个实体的映射配置

以 ExampleIdentity 为例,使用通用扩展完成配置:

public void Configure(EntityTypeBuilder<ExampleIdentity> builder)
{
    // 配置复合主键与表映射
    builder.ConfigureCompositeId(e => e.Id, "Example");

    // 配置其他领域属性的列映射
    builder.Property(e => e.Comment).HasColumnName("COMMENT").IsRequired(false);
}

4. 实体关联查询配置

如果需要关联其他实体(如 RelatedEntity),直接使用强类型 ID 作为外键属性,EF Core 会自动关联对应的数据库列:

// 关联实体定义
public class RelatedEntity
{
    public ExampleIdentityKey Id { get; private set; }
    public ExampleIdentityKey ExampleId { get; private set; }
    public ExampleIdentity? Example { get; private set; }

    // 构造函数省略
}

// 关联映射配置
public void Configure(EntityTypeBuilder<RelatedEntity> builder)
{
    builder.ConfigureCompositeId(e => e.Id, "Related");

    // 配置外键关联
    builder.HasOne(e => e.Example)
           .WithMany() // 根据实际业务关系调整为 WithMany(e => e.RelatedEntities)
           .HasForeignKey(e => e.ExampleId)
           .HasPrincipalKey(e => e.Id);
}

5. 表拆分(SplitToTable)支持

如果需要将实体属性拆分到多个表,只需在配置中指定属性对应的表即可(主键字段必须保留在主表):

public void Configure(EntityTypeBuilder<ExampleIdentity> builder)
{
    builder.ConfigureCompositeId(e => e.Id, "Example");

    // 将 Comment 属性拆分到单独的表 Example_Comments
    builder.Property(e => e.Comment).ToTable("Example_Comments");
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 13:52:34