首页 > 解决方案 > EF 核心实体 ID 作为具有标识列的自定义类

问题描述

我想在我的实体模型中使用强类型 ID,映射到DB 中的自动递增int(例如 MS SQL Identity 列)。但 EF Core 3.1 不支持自定义类型的标识:

public class Vendor
{
    public VendorId Id { get; private set; }
    public string CompanyName { get; set; }
}

public class VendorId
{
    public int Value { get; }

    public VendorId(int value)
    {
        Value = value;
    }
}

public void Configure(EntityTypeBuilder<Vendor> vendorEntity)
{
    vendorEntity.HasKey(vendor => vendor.Id);
    vendorEntity.Property(vendor => vendor.Id)
                .HasConversion(vendorId => vendorId.Value, dbValue => new VendorId(dbValue))
                .UseIdentityColumn();
} 

有了这个模型,我得到了例外:

标识值生成不能用于实体类型“供应商”上的属性“Id”,因为该属性类型是“供应商Id”。标识值生成只能与有符号整数属性一起使用。

我还尝试映射到私有整数支持字段int id,但是我不能在 EF 查询中使用 Id 属性。所以它看起来不是一个解决方案。

类似的问题是当我尝试 HiLo 密钥生成时。

您对如何解决这个问题有任何想法吗?

标签: c#entity-frameworkentity-framework-core

解决方案


我使用 c# 9 记录使用的解决方案(在 ef core 5 中):

public abstract record StronglyTypedId<TValue>(TValue Value) where TValue : notnull
{
    public override string ToString() => Value.ToString();
}

使用抽象实体模型:

public abstract class Entity<TId, T> where TId: StronglyTypedId<T>
{
    T _Id;
    public virtual TId Id 
    {
        get { return (TId)Activator.CreateInstance(typeof(TId), new object[] {_Id}); }
    }
 
}

然后是一个示例实体模型

using TId = Int32;

public record EntityTypeId(TId Value) : StronglyTypedId<TId>(Value);

public class EntityName<EntityTypeId, TId>
{
    private EntityName() {} //for ef core
}

然后在模型构建器中(可以再次成为抽象/基础模型构建器)

    builder.Ignore(e => e.Id);
    builder
        .Property("_Id")
        .HasColumnName("Id")
        .UseIdentityColumn();
    builder.HasKey("_Id");

这确实意味着从数据库(通过命令或存储库)检索时,您需要使用名称,例如

public async Task<EntityName> GetEntity(EntityTypeId typedId)
{
var entity = await context.EntityName
    .FirstOrDefaultAsync(x => EF.Property<int>(x, "_Id") == typedId.Value);
return entity;
}

不完美但有效


推荐阅读