如何配置Entity Framework Core以支持自定义值对象类型?
问题:EF Core 配置自定义值对象类型的属性
我尝试创建迁移,但不知道如何配置Entity Framework以支持带有自定义类型的属性。
我的值对象BrandName类:
public class BrandName : ValueObject<BrandName> { public string Value { get; } private BrandName(string name) { Value = name; } public static Result<BrandName> Create(string brandName) { brandName = (brandName ?? string.Empty).Trim(); if (String.IsNullOrEmpty(brandName)) { return Result.Fail<BrandName>(BrandValidationValues.BrandNameEmpty); } if (brandName.Length > BrandValidationValues.BrandNameLength) { return Result.Fail<BrandName>(BrandValidationValues.BrandNameTooLong); } return Result.Ok(new BrandName(brandName)); } protected override bool EqualsCore(BrandName other) { return Value.Equals(other.Value, StringComparison.InvariantCultureIgnoreCase); } protected override int GetHashCodeCore() { return Value.GetHashCode(); } public static implicit operator string(BrandName brandName) { return brandName.Value; } public static explicit operator BrandName(string brandName) { return Create(brandName).Value; } }
我的实体CatalogBrand类:
public class CatalogBrand : Entity { private string _name; public virtual BrandName Name { get => (BrandName)_name; set => _name = value; } }
Entity Framework配置:
class BrandEntityTypeConfiguration : IEntityTypeConfiguration<CatalogBrand> { public void Configure(EntityTypeBuilder<CatalogBrand> builder) { builder.ToTable("Brand"); builder.HasKey(ci => ci.Id); builder.Property(ci => ci.Id) .UseHiLo("brand_hilo") .IsRequired(); builder.Property(cb => cb.Name) .IsRequired() .HasMaxLength(100); } }
遇到的错误:
属性'CatalogBrand.Name'的类型为'BrandName',当前数据库提供程序不支持该类型。请更改属性CLR类型,或使用'[NotMapped]'特性,或在'OnModelCreating'中使用'EntityTypeBuilder.Ignore'忽略该属性。
解决方案
EF Core 默认不识别自定义值对象类型,可通过以下两种方案解决:
方案1:使用值转换映射字符串类型
修改BrandEntityTypeConfiguration配置,为Name属性添加值转换逻辑,实现BrandName与string的双向转换:
class BrandEntityTypeConfiguration : IEntityTypeConfiguration<CatalogBrand> { public void Configure(EntityTypeBuilder<CatalogBrand> builder) { builder.ToTable("Brand"); builder.HasKey(ci => ci.Id); builder.Property(ci => ci.Id) .UseHiLo("brand_hilo") .IsRequired(); // 配置值转换:BrandName <-> string builder.Property(cb => cb.Name) .IsRequired() .HasMaxLength(100) .HasConversion( // 写入数据库时,将BrandName转为字符串 brandName => brandName.Value, // 读取数据库时,将字符串转为BrandName实例 dbValue => BrandName.Create(dbValue).Value ); } }
方案2:映射私有字段并忽略公开属性
直接映射实体的私有字段_name,同时标记公开的Name属性为不映射:
class BrandEntityTypeConfiguration : IEntityTypeConfiguration<CatalogBrand> { public void Configure(EntityTypeBuilder<CatalogBrand> builder) { builder.ToTable("Brand"); builder.HasKey(ci => ci.Id); builder.Property(ci => ci.Id) .UseHiLo("brand_hilo") .IsRequired(); // 映射私有字段,指定数据库列名为Name builder.Property<string>("_name") .IsRequired() .HasMaxLength(100) .HasColumnName("Name"); // 忽略公开的Name属性 builder.Ignore(cb => cb.Name); } }
注意事项
- 方案1中使用
BrandName.Create(dbValue).Value时,需确保数据库中的字符串符合校验规则,否则会抛出异常;如需容错,可在转换逻辑中添加错误处理。 - 值转换功能支持EF Core 2.x及以上版本,低版本需自定义类型转换器。
内容的提问来源于stack exchange,提问作者Vlad
相关产品推荐
相关产品推荐

