4
votes

Suppose that you have two entities derived from an abstract base class and you want implement Table-Per-Concrete-Type. Entities like below:

public abstract class EntityBase
{
   public int Id { get; set; }

   public string CreatedBy { get; set; }

   public DateTime CreatedAt { get; set; }
}

public class Person : EntityBase
{
   public string Name { get; set; }
}
public class PersonStatus : EntityBase
{
   public string Title { get; set; }
}

And you don’t want to use attribute in the abstract base class(EntityBase), you want to map EntityBase class in dbcontext only once for all entities. How to change the code below :

public class PeopleDbContext : DbContext
{
   public DbSet<Person> People { get; set; }

   protected override void OnModelCreating(ModelBuilder modelBuilder)
   {
      base.OnModelCreating(modelBuilder);

      // Entity base class mapping(only once)

      modelBuilder.Entity<Person>(e =>
      {
        e.Property(x => x.Name)
            .IsRequired()
            .HasMaxLength(100);
      });
      modelBuilder.Entity<PersonStatus>(e =>
      {
        e.Property(x => x.Title)
            .IsRequired()
            .HasMaxLength(100);
      });
  }

}
1
Did you try anything? I have setups like this and the Id is picked up by convention. - Henk Holterman
Yes, when i tried to map(fluent) EntityBase class in dbcontext, ef created another table for EntityBase class. Before this, I implemented with fluent nhibernate and that worked properly with using ClassMap. Also, i used ef 6 “builder.Types<EntityBase>(..)”. It worked as i want. But with ef core i couldn’t make it. - adem caglin

1 Answers

3
votes

Here is an answer to your question..

You need to write Configurations for your BaseClass:

public class EntityBaseConfiguration<TBase> : IEntityTypeConfiguration<TBase>
    where TBase : EntityBase
{
    public virtual void Configure(EntityTypeBuilder<TBase> builder)
    {
        builder.HasKey(b => b.Id);
        builder.Property(b => b.CreatedBy)
            .HasColumnType("varchar(50)");
        builder.Property(b => b.CreatedAt)
            .HasColumnType("datetime2");
    }
}

After that, you can write your concrete Configuration-Class foreach Table which inherits from EntityBase like so:

public class PersonConfig : BaseConfig<Person>
{
    public override void Configure(EntityTypeBuilder<Person> builder)
    {
        base.Configure(builder);
        builder.Property(e => e.Name)
            .HasColumnType("varchar(100)")
            .IsRequired();
    }
}

To invoke your configuration in your dbContext you can call ApplyConfiguration:

public class PeopleDbContext : DbContext
{
    public DbSet<Person> People { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.ApplyConfiguration(new PersonConfig());
    }
}