I have a problem similar to Entity Framework 5: Using DatabaseGeneratedOption.Computed option.
I want to have a creation and modification dates on every table in database. This is what I have now:
public class BaseEntity
{
[NotNull]
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public Guid Id { get; set; } = Guid.NewGuid();
//Note: uint timestamp is specific to PostgreSQL database as it maps to it's internal xmin column. For MsSQL you would use byte[] which is the EF standard.
[Timestamp]
public uint Version { get; set; }
public DateTime Created { get; set; } = DateTime.UtcNow;
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime? Modified { get; set; }
}
The Created value works well but the Modified remains unset. I read that [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
does not actually guarantee that the update mechanism will be set-up, but I do not know how to set it up using NPGSQL.
I prefer to avoid modifying migrations and using the least amount of fluent configuration I can. If fluent is required, would it be possible to make it apply to all tables with a single command or do I have to apply it to every property separately?
Here is a possible solution for your "Modified" problem. Modify your DbContext
like this:
public class MyContext : DbContext
{
public override int SaveChanges()
{
this.DoCustomEntityPreparations();
return base.SaveChanges();
}
public override int SaveChanges(bool acceptAllChangesOnSuccess)
{
this.DoCustomEntityPreparations();
return base.SaveChanges(acceptAllChangesOnSuccess);
}
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
this.DoCustomEntityPreparations();
return await base.SaveChangesAsync(cancellationToken);
}
private void DoCustomEntityPreparations()
{
var modifiedEntitiesWithTrackDate = this.ChangeTracker.Entries().Where(c => c.State == EntityState.Modified);
foreach (var entityEntry in modifiedEntitiesWithTrackDate)
{
// Do not confuse "modified" track state and "modified" your property
if (entityEntry.Properties.Any(c => c.Metadata.Name == "Modified"))
{
entityEntry.Property("Modified").CurrentValue = DateTime.UtcNow;
}
}
}
}
This will look at all tracked entities that have been modified, search for "Modified" property on them and set it to the current date just before sending it to the database.
You could do the same automation with "Created" by looking at tracked entities in "Created" state. Again, do not confuse "created" as tracked entity state with your property with the same name.