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

时间:2018-11-11 05:17:06

标签: c# sql-server entity-framework entity-framework-core ef-core-2.0

我在SQL Server中有一个可为空的 public uint ReadInt(int Address) { OpenProcessMemory(); int BytesRead = 0; byte[] Data = new byte[4]; ReadProcessMemory((int)PHandle, Address, Data, 4, ref BytesRead); CloseProcessMemory(); return BitConverter.ToUInt32(Data, 0); } 列,我正在以EF代码优先的方式映射到 public enum Offsets : uint { Animation = 0x1494198, P1 = 0x68, P2 = 0x70, P3 = 0x28, P4 = 0x378, P5 = 0x522, } 。但是,此属性实际上在许多其他实体派生的基类中。

[DllImport("kernel32.dll")]
public static extern int ReadProcessMemory(IntPtr hProcess, IntPtr 
lpBaseAddress, [In, Out] byte[] bBuffer, uint size, out IntPtr 
lpNumberOfBytesRead);

上面的行对于每个表重复很多次。有没有办法告诉EF这是基类属性,因此只能声明一次映射?

3 个答案:

答案 0 :(得分:2)

当然可以。由于缺少自定义约定,因此可以通过“典型” modelBuilder.Model.GetEntityTypes()循环来实现。像这样(只需更改基类和属性名称):

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);

您还可以考虑使用开箱即用的GuidString转换器提供的EF核心:

var valueConverter = new GuidToStringConverter();

答案 1 :(得分:0)

更好地进行下一个计算属性:

[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();
}

答案 2 :(得分:0)

另一种方法是拥有匹配的基类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
    }
}

(假设您的基类称为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();
    }
}