Entity Framework Core Modified and Created fields with Concurrency Tokens

entity-framework-core optimistic-concurrency


Hi! I have Entity Framework Core 2.xx ORM solution and all my objects in the model have Created (UTC timestamp of db creation time - never updated) and Modified field (updated always when entity is updated). I read some proposal implementation for this very common problem and it looks like the framework doesn't support it well yet because there is no good way to do that without defining mapping separately for each of the entities. One workaround that I found was to define a non-mapped super class and then manually generate value generation step with it. Because db UTCDatetime is db side feature I have to also manually define that I use utc datetime function in db. I know how to do that in model generation with fluent api like this:

// this example is missing the definition of what is db call:

        .Property(p => p.Timestamp)

and I can add utc time generation in migration like this:

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

But my question is: How can I do that if I do everything automatically with MyBaseObject super class? (it has these Modified and Created fields and is not mapped itself). I do it currently like this, but I don't know how to define backend Created field call '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));

                    guidProperty.ValueGenerated = ValueGenerated.OnAdd;

                    modifiedProperty.ValueGenerated = ValueGenerated.OnAddOrUpdate;
                    modifiedProperty.IsReadOnlyBeforeSave = true;

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

                    entityType.AddProperty("GUID", typeof(Guid));
                    entityType.AddProperty("Created", typeof(DateTime));
                    entityType.AddProperty("Modified", typeof(DateTime));
7/14/2017 12:02:16 PM

Popular Answer

I would suggest creating a constrained generic method or class, and using a normal fluent API inside to configure the common attributes.

For instance, a generic class receiving ModelBuilder in the constructor:

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

            .Property(e => e.GUID)

            .Property(e => e.Created)

            .Property(e => e.Modified)

and call it with reflection inside OnModelCreating:

foreach (var type in modelBuilder.Model.GetEntityTypes().Where(t => t.ClrType.IsSubclassOf(typeof(MyBaseObject))))
    Activator.CreateInstance(typeof(MyBaseObjectConfiguration<>).MakeGenericType(type.ClrType), modelBuilder);
7/14/2017 3:24:18 PM

Related Questions


Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow