Search code examples
c#entity-framework-coreef-code-firstentity-framework-migrations

Apply configuration to base class without creating a table


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.


Solution

  • 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.