I am making an application, following the principles of Entity Framework code first, using the Migrations feature.
To avoid having the same code in every class, I have made a base class called AuditableEntity
which contains the basic properties that all (auditable) entities must contain:
public abstract class AuditableEntity
{
public int Id { get; private set; }
public string CreatedBy { get; private set; }
public DateTime CreatedDtm { get; private set; }
}
Now the field CreatedBy
should have a default SQL value of CURRENT_USER
.
And the field CreatedDtm
should have a default SQL value of GETDATE()
.
Normally I would make a configuration file for the table, in which this is done, like this:
public class AuditableEntityConfiguration : IEntityTypeConfiguration<AuditableEntity>
{
public void Configure(EntityTypeBuilder<AuditableEntity> builder)
{
builder.Property(e => e.CreatedBy).HasDefaultValueSql("USER_NAME()");
builder.Property(e => e.CreatedDtm).HasDefaultValueSql("GETDATE()");
}
}
But if I do this, Entity Framework wants to create a table called AuditableEntity
. This is (obviously) not my intention. I want AuditableEntity
to be an abstract base, not an actual entity. Or in other words, I want it to provide some very basic shared functionality for my actual entities.
Is there any way I can do something similar, which allows all classes inheriting from AuditableEntity
to get the default SQL values described above?
I would like it done in a way, so that the logic applies on database level, so it is not as simple as setting the values in the C# code.
You can create a generic class, that will avoid to create a config class for each type but you will need to register the config for each type:
public class AuditableEntityConfiguration<T> : IEntityTypeConfiguration<T> where T : AuditableEntity
{
public void Configure(EntityTypeBuilder<T> builder)
{
builder.Property(e => e.CreatedBy).HasDefaultValueSql("USER_NAME()");
builder.Property(e => e.CreatedDtm).HasDefaultValueSql("GETDATE()");
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new AuditableEntityConfiguration<DerivedClass1>());
modelBuilder.ApplyConfiguration(new AuditableEntityConfiguration<DerivedClass2>());
}
If speed is not important then you can always use reflection to get all types that derive from AuditableEntity and register the configurations dynamically.