I have a BaseClass, which is abstract, and has many abstract properties.
I have a dozen or so (it will probably grow) entities that are part of the Entity Framework that each derive from BaseClass.
I'm trying to avoid having to do:
modelBuilder.Entity<Entity1>().HasKey(t => t.Id);
modelBuilder.Entity<Entity2>().HasKey(t => t.Id);
modelBuilder.Entity<Entity3>().HasKey(t => t.Id);
...
for each property and each entity, since that seems very wasteful and creates a lot of code duplication. I experimented with getting all the Entities in a namespace that derive from the BaseClass by:
var derivedEntities = Assembly.GetExecutingAssembly().GetTypes().
Where(t => t.Namespace == "My.Entities" && t.IsAssignableFrom(typeof(BaseClass)));
However, the next logical steps seems to be:
foreach (var entity in derivedEntities)
{
modelBuilder.Entity<entity>().HasKey(t => t.Id);
}
but will not compile, because
"entity is a variable, but is used like a type".
Configuring a primary key By convention, a property named Id or <type name>Id will be configured as the primary key of an entity. Owned entity types use different rules to define keys. You can configure a single property to be the primary key of an entity as follows: Data Annotations.
Property Mapping. The Property method is used to configure attributes for each property belonging to an entity or complex type.
Data annotations and the fluent API can be used together, but Code First gives precedence to Fluent API > data annotations > default conventions. Fluent API is another way to configure your domain classes.
The Entity Framework Core Fluent API HasDefaultValue method is used to specify the default value for a database column mapped to a property.
I figured it out:
public class BaseObjectConfiguration<TEntity> : EntityTypeConfiguration<TEntity>
where TEntity : BaseObject
{
public BaseObjectConfiguration()
{
// Mapped
HasKey(t => t.Id);
Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(t => t.Name).IsRequired().HasMaxLength(100);
Property(t => t.DisplayName).IsOptional().HasMaxLength(100);
Property(t => t.Alias).IsOptional().HasMaxLength(100);
Property(t => t.SourceId).IsRequired();
Property(t => t.AccessLevel).IsRequired();
Property(t => t.CreatedOn).IsOptional();
Property(t => t.CreatedBy).IsOptional().HasMaxLength(50);
Property(t => t.ModifiedOn).IsOptional();
Property(t => t.ModifiedBy).IsOptional().HasMaxLength(50);
//// Base Entity Ignores (Not Mapped)
Ignore(t => t.SomeIgnoredProperty);
Ignore(t => t.SomeIgnoredProperty2);
Ignore(t => t.SomeIgnoredProperty3);
}
}
Then, in OnModelCreating inside of the DbContext:
modelBuilder.Configurations.Add(new BaseObjectConfiguration<Entity1>());
modelBuilder.Configurations.Add(new BaseObjectConfiguration<Entity2>());
modelBuilder.Configurations.Add(new BaseObjectConfiguration<Entity3>());
modelBuilder.Configurations.Add(new BaseObjectConfiguration<Entity4>());
...
// Specific mappings options for each entity:
modelBuilder.Entity<Entity1>().HasRequired(t => t.NodeTypeEntity).
WithMany(t => t.Nodes).HasForeignKey(t => t.NodeTypeId);
modelBuilder.Entity<NWatchNode>().HasOptional(t => t.Parent).
WithMany(t => t.Children).HasForeignKey(t => t.ParentId);
...
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