如何以比我现在更有效的方式将数据库列映射到 EF 模型 属性

How to map database column to EF model property in a more efficient way than I'm doing now

我在 SQL 服务器中有一个可为 null 的 varchar(max) 列,我正在映射到 EF 代码优先中的 Guid?。然而,这个 属性 实际上是在许多其他实体派生自的基础 class 中。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Model1>().Property(e => e.Property1).HasConversion(p => p.ToString(), p => (Guid?)Guid.Parse(p));
}

以上行对每个 table 重复多次。有没有办法告诉 EF 这是一个基数 class 属性 因此映射只能声明一次?

当然可以。由于缺少自定义约定,它是通过 "typical" modelBuilder.Model.GetEntityTypes() 循环实现的。像这样(只需更改基础 class 和 属性 名称):

var entityTypes = modelBuilder.Model.GetEntityTypes()
    .Where(t => t.ClrType.IsSubclassOf(typeof(BaseClass)));

var valueConverter = new ValueConverter<Guid, string>(
    v => v.ToString(), v => (Guid?)Guid.Parse(v));

foreach (var entityType in entityTypes)
    entityType.FindProperty(nameof(BaseClass.Property1)).SetValueConverter(valueConverter);

您也可以考虑使用开箱即用的 EF Core GuidString 转换器:

var valueConverter = new GuidToStringConverter();

最好进行下一次计算属性:

[Column("Property1")]
public string Property1Raw { get; set; }

[IgnoreDataMember]
public Guid? Property1
{
    get => Guid.TryParse(Property1AsString, out Guid result) ? result : (Guid?)null;
    set => Property1Raw = value?.ToString();
}

另一种方法是有一个匹配的基础 class IEntityTypeConfiguration:

internal class EntityConfiguration<T> : IEntityTypeConfiguration<T> where T : Entity
{
    public virtual void Configure(EntityTypeBuilder<T> builder)
    {
        builder.Property(e => e.Property1).HasConversion(p => p.ToString(), p => (Guid?)Guid.Parse(p));
        // ... Other base-specific config here
    }
}

(假设这里你的基地 class 被称为 Entity - 根据需要改变)。

当您使用分解实体配置的模式时,这种方法效果更好,因此您的配置可能是这样的:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.ApplyConfiguration(new Model1EntityConfiguration());
    modelBuilder.ApplyConfiguration(new Model2EntityConfiguration());
    // ...
}

...

internal sealed class Model1EntityConfiguration : EntityConfiguration<Model1>
{
    public override void Configure(EntityTypeBuilder<Model1> builder)
    {
        base.Configure(builder); // <-- here's the key bit
        // ...; e.g.
        builder.Property(c => c.Name).HasMaxLength(80).IsRequired();
    }
}