JB's
JB's

Reputation: 626

EF Core Fluent API Configurations with Inheritance

EF CORE Fluent Api Configuration in separate files are Working fine with simple classes Ref #1 && Ref # 2. The problem comes when entities are Inherited from KeyedEntity or AuditableEntity

class abstract KeyedEntity<TValue> {
      public TValue Id {get; set;}
}

class abstract  AuditableEntity<TValue> : KeyedEntityBase<TValue>{
      public DateTime DateCreated {get; set;}
      public DateTime DateModified {get; set;}
}

Mapper Goes Something like this

public class KeyedEntityMap<TEntity, TId>
    : IEntityTypeConfiguration<TEntity> where TEntity
    : KeyedEntityBase<TId> where TId : struct
{
    public void Configure(EntityTypeBuilder<TEntity> builder)
    {
        // Primary Key
        builder.HasKey(t => t.Id);

        // Properties
        builder.Property(t => t.Id).HasColumnName("id").ValueGeneratedOnAdd();
    }
}

public class AuditableEntityMap<TEntity, TId>
    : IEntityTypeConfiguration<TEntity>    where TEntity 
    : AuditableEntity<TId>    where TId : struct
{
    public void Configure(EntityTypeBuilder<TEntity> builder)
    {
        // Properties
        builder.Property(t => t.DateCreated).HasColumnName("DateCreated");
        builder.Property(t => t.DateModified).HasColumnName("DateModified");           
    }
}

Now the Problem Occurs with the Entity that inherits from AuditableEntity. I need to register Map from that Particular Enitity class along with AuditableEntityMap class and KeyedEntityMap class.

Now I can either forget about Map Inheritance and merge all the complex inheritance Maps in the entity class, which I don't want to do and respect DRY . The problem with complex inheritance is its not registering my entity maps

Upvotes: 6

Views: 4289

Answers (1)

Ivan Stoev
Ivan Stoev

Reputation: 205619

There are several ways you can achieve DRY for base entity configuration.

Bit the closest to your current design is to simply follow the entity hierarchy in the configuration classes:

public class KeyedEntityMap<TEntity, TId> : IEntityTypeConfiguration<TEntity>
    where TEntity : KeyedEntityBase<TId>
    where TId : struct
{
    public virtual void Configure(EntityTypeBuilder<TEntity> builder)
    //       ^^^
    {
        // Primary Key
        builder.HasKey(t => t.Id);

        // Properties
        builder.Property(t => t.Id).HasColumnName("id").ValueGeneratedOnAdd();
    }
}

public class AuditableEntityMap<TEntity, TId> : KeyedEntityMap<TEntity, TId>
    //                                                 ^^^
    where TEntity : AuditableEntity<TId>
    where TId : struct
{
    public override void Configure(EntityTypeBuilder<TEntity> builder)
    //       ^^^
    {
        base.Configure(builder); // <<<
        // Properties
        builder.Property(t => t.DateCreated).HasColumnName("DateCreated");
        builder.Property(t => t.DateModified).HasColumnName("DateModified");           
    }
}

and then for specific entity that needs additional configuration:

public class Person : AuditableEntity<int>    
{
    public string Name { get; set; }
}

you would register

public class PersonEntityMap : AuditableEntityMap<Person, int>
{
    public override void Configure(EntityTypeBuilder<Person> builder)
    {
        base.Configure(builder);
        // Properties
        builder.Property(t => t.Name).IsRequired();
        // etc...
    }
}

Upvotes: 11

Related Questions