I have database objects that all inherit from a parent class with some base properties.
Base Entity
public abstract class Entity : IAuditable
{
public int Id { get; set; }
public string CreatedBy { get; set; }
public int? CreatedDate { get; set; }
public string UpdateBy { get; set; }
public int? UpdatedDate { get; set; }
}
Base Entity Configuration file
public EntityConfiguration()
{
HasKey(e => e.Id);
Property(e => e.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(e => e.CreatedBy)
.IsUnicode(false)
.HasMaxLength(255);
Property(e => e.UpdatedBy)
.IsUnicode(false)
.HasMaxLength(255);
}
I subclass entity on all the child classes to inherit the common properties
public class User : Entity
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
DbContext
public class SomeContext : DbContext
{
public SomeContext() : base("name=DefaultConnection")
{
}
public static SomeContext Create()
{
return new SomeContext();
}
public DbSet<Collaboration> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new EntityConfiguration());
modelBuilder.Configurations.Add(new UserConfiguration());
}
}
When I create the migrations It will create all the inherited properties correctly but it still creates the parent class (Entity) even though I don't have a DbSet. If I remove the line that adds the configuration settings in the OnModelCreating method I don't get the max lengths and Unicode settings.
Is there a way to use the configuration properties without actually creating the parent table and without adding the configurations to all the subclass configuration files.
If anyone is interested here are the two solutions that I came up with. I opted for the second one as it seems to be the more accurate solution.
Solution 1
Use the Types configuration to the base class and anything inheriting the base class will also inherit the configuration.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Types<Entity>().Configure(c =>
{
c.HasKey(e => e.Id);
c.Property(e => e.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
c.Property(e => e.CreatedBy)
.IsUnicode(false)
.HasMaxLength(255);
c.Property(e => e.UpdatedBy)
.IsUnicode(false)
.HasMaxLength(255);
});
modelBuilder.Configurations.Add(new UserConfiguration());
}
Solution 2
Use a combination of Generics, Interfaces and Inheritance to create a base EntityTypeConfiguration class. Then have other entity type configurations classes inherit from it.
public interface IEntity
{
int Id { get; set; }
}
public interface IAuditable
{
string CreatedBy { get; set; }
DateTime? CreatedDate { get; set; }
string UpdatedBy { get; set; }
DateTime? UpdatedDate { get; set; }
}
public class EntityConfiguration<T> : EntityTypeConfiguration<T> where T : class, IEntity, IAuditable
{
public EntityConfiguration()
{
HasKey(e => e.Id);
Property(e => e.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(e => e.CreatedBy)
.IsUnicode(false)
.HasMaxLength(255);
Property(e => e.UpdatedBy)
.IsUnicode(false)
.HasMaxLength(255);
}
}
This approach of inheritance with EF Code first is the Table per Concrete Type TPC Hierarchy
In the link you can find all the logic with examples on how to implement it. I know I shouldn't provide links but check the link, it has everything :)
Examples, Code explanation, graphs and images. I think it is exactly what you need to understand the TPC.