实体框架核心使用并发标记修改和创建的字段

时间:2017-07-14 12:02:16

标签: entity-framework-core optimistic-concurrency

嗨! 我有Entity Framework Core 2.xx ORM解决方案,模型中的所有对象都已创建(数据库创建时间的UTC时间戳 - 从未更新)和修改字段(更新实体时始终更新)。 我为这个非常常见的问题阅读了一些提议实现,看起来框架还不能很好地支持它,因为如果没有为每个实体单独定义映射,就没有好办法。 我找到的一个解决方法是定义一个非映射的超类,然后用它手动生成值生成步骤。因为db UTCDatetime是数据库端功能,我还必须手动定义我在db中使用utc datetime函数。我知道如何在模型生成中使用流畅的api这样做:

//这个例子缺少db调用的定义:

modelBuilder.Entity<MyObject>()
        .Property(p => p.Timestamp)
        .ValueGeneratedOnAddOrUpdate()
        .IsConcurrencyToken();

我可以在迁移中添加utc时间生成,如下所示:

AddColumn("MyObject", "Created", n => n.DateTime(nullable: false, defaultValueSql: "GETUTCDATE()"));`

但我的问题是:如果我使用MyBaseObject超类自动完成所有操作,我该怎么办呢? (它具有这些已修改和已创建的字段,并且未自行映射)。我现在这样做,但我不知道如何定义后端创建字段调用'GetUTCDate()'

if (entityType.ClrType.IsSubclassOf(typeof(MyBaseObject)))
{
                    var guidProperty = entityType.FindProperty(nameof(MyBaseObject.GUID));
                    var createdProperty = entityType.FindProperty(nameof(MyBaseObject.Created));
                    var modifiedProperty = entityType.FindProperty(nameof(MyBaseObject.Modified));

                    entityType.AddKey(guidProperty);
                    entityType.SetPrimaryKey(guidProperty);                    
                    guidProperty.ValueGenerated = ValueGenerated.OnAdd;


                    modifiedProperty.ValueGenerated = ValueGenerated.OnAddOrUpdate;
                    modifiedProperty.IsReadOnlyBeforeSave = true;
                    //modifiedProperty.SetValueGeneratorFactory();

                    createdProperty.ValueGenerated = ValueGenerated.OnAdd;
                    createdProperty.IsReadOnlyBeforeSave = true;

                    entityType.AddProperty("GUID", typeof(Guid));
                    entityType.AddProperty("Created", typeof(DateTime));
                    entityType.AddProperty("Modified", typeof(DateTime));
                    entityType.AddIndex(modifiedProperty);
                    entityType.AddIndex(createdProperty);
}

1 个答案:

答案 0 :(得分:3)

我建议创建一个约束泛型方法或类,并在里面使用普通的流畅API来配置公共属性。

例如,在构造函数中接收ModelBuilder的泛型类:

class MyBaseObjectConfiguration<TEntity> where TEntity : MyBaseObject
{
    public MyBaseObjectConfiguration(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<TEntity>()
            .HasKey(e => e.GUID);

        modelBuilder.Entity<TEntity>()
            .Property(e => e.GUID)
            .ValueGeneratedNever();

        modelBuilder.Entity<TEntity>()
            .Property(e => e.Created)
            .ValueGeneratedOnAdd()
            .HasDefaultValueSql("GETUTCDATE()");

        modelBuilder.Entity<TEntity>()
            .Property(e => e.Modified)
            .ValueGeneratedOnAddOrUpdate()
            .HasDefaultValueSql("GETUTCDATE()")
            .IsConcurrencyToken();
    }
}

并使用OnModelCreating内的反射调用它:

foreach (var type in modelBuilder.Model.GetEntityTypes().Where(t => t.ClrType.IsSubclassOf(typeof(MyBaseObject))))
    Activator.CreateInstance(typeof(MyBaseObjectConfiguration<>).MakeGenericType(type.ClrType), modelBuilder);