I have a class TypeEntity
that will act as the base class for several dozen entities. I'm using TPC, so I need to map all the properties on the base class to the table with the name of the concrete class, and set the Key
field to be database generated.
Currently I'm doing this with an EntityTypeConfiguration
for each entity type that looks like this:
class LineItemType : EntityTypeConfiguration<Models.LineItemType>
{
public LineItemType()
{
this.Property(e => e.Key)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
this.Map(e => e.MapInheritedProperties()
.ToTable(nameof(LineItemType)));
}
}
This works fine, but is very repetitive. I have to remember to create a configuration class for every type that inherits from TypeEntity
, set the key, and map the inherited properties. This seems like an ideal case for a custom Convention
.
I created a TypeEntityTpcConvention
Convention
as follows:
class TypeEntityTpcConvention : Convention
{
public TypeEntityTpcConvention()
{
this.Types<TypeEntity>()
.Configure(e => e.Property(p => p.Key)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity));
}
}
Which works to set Key
as database generated, but I can't find any way to access the table mappings for properties from inside a convention.
Ideally, I'd expect something like this:
this.Types<TypeEntity>()
.Configure(e => e.MapInheritedProperties()
.ToTable(e.ClrType.Name));
Or even a call like this for each property that needs to be mapped:
this.Types<TypeEntity>()
.Configure(e => e.Property(p=>p.Key)
.ToTable(e.ClrType.Name));
Neither of which seems to exist. Is there any way for me to control the mapping of properties from inside a Convention
?
After some additional research, it looks like there are more advanced convention options available as IStoreModelConvention
and IConceptualModelConvention
, but useful documentation for how to use these is severely lacking. After several hours poking through them with breakpoints and watch windows, I haven't figured out how to control column mapping using these interfaces either.
My current solution is to use reflection to find all types that inherit from TypeEntity
in OnModelCreating
, and map the properties to the correct table. This works, but I would prefer to use a convention if possible, as this really seems like the type of thing conventions were made for. I feel like I am missing something obvious.
As far as I can see, you could just write the type configuration in the OnModelCreating
method of your DbContext
and it is very similar to the code you already mentioned in the question.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Types<TypeEntity>().Configure(c =>
{
c.HasKey(p => p.Key);
// probably not needed, but won't do any harm
c.Property(p => p.Key).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
c.ToTable(c.ClrType.Name);
});
}
If there is any problem with this approach, let me know and I'll re-visit the topic.
Edit:
The exact same principle can be applied with conventions:
class TypeEntityConvention : Convention
{
public TypeEntityConvention()
{
this.Types<TypeEntity>().Configure(c =>
{
c.HasKey(p => p.Key);
c.Property(p => p.Key).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
c.ToTable(c.ClrType.Name);
});
}
}
and
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Add<TypeEntityConvention>();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With