Reputation: 592
I have problem with inheritance code first. I have base class which look like this:
public abstract class BaseEntity
{
public DateTime? DateCreated { get; set; }
public string UserCreatedId { get; set; }
public DateTime? DateModified { get; set; }
public string UserModifiedId { get; set; }
public virtual UserState UserCreated { get; set; }
public virtual UserState UserModified { get; set; }
}
and i have Inherited it and this give me a additional column with name UserCreated_userStateId and UserModified_UserStateId. So I try fluent API like this:
modelBuilder.Entity<BaseEntity>().HasOptional(x => x.UserCreated).WithMany().HasForeignKey(x => x.UserCreatedId);
modelBuilder.Entity<BaseEntity>().HasOptional(X => X.UserModified).WithMany().HasForeignKey(x => x.UserModifiedId);
But this give me error: "One or more validation errors were detected during model generation:
BaseEntity: : EntityType 'BaseEntity' has no key defined. Define the key for this EntityType. BaseEntities: EntityType: EntitySet 'BaseEntities' is based on type 'BaseEntity' that has no keys defined." How to avoid define the key and only change mapping of property? I have key in derived class.
Upvotes: 2
Views: 1678
Reputation: 13458
You can wrap your base class configuration in a generic method and call it for each concrete entity type.
static void ConfigureBaseEntity<TDerived>(EntityTypeConfiguration<TDerived> entityTypeConfiguration) where TDerived : BaseEntity
{
// your base class configuration
entityTypeConfiguration.HasOptional(x => x.UserCreated).WithMany().HasForeignKey(x => x.UserCreatedId);
entityTypeConfiguration.HasOptional(X => X.UserModified).WithMany().HasForeignKey(x => x.UserModifiedId);
}
Call for each concrete entity type
public class DerivedEntity : BaseEntity
{
public int Id { get; set; }
}
//...
ConfigureBaseEntity(modelBuilder.Entity<DerivedEntity>());
Edit
Maybe the Types
configuration is enough for your purpose.
modelBuilder.Types<BaseEntity>().Configure(entityTypeConfiguration => /* configure using entityTypeConfiguration */);
Otherwise, as commented, you may need reflection. For example, lets say all your derived classes are in the same assembly as the BaseEntity
class and the ConfigureBaseEntity
method from above is in class BaseEntityConfiguration
.
var entityMethod = typeof(DbModelBuilder).GetMethod("Entity");
var configurationMethod = typeof(BaseEntityConfiguration).GetMethod("ConfigureBaseEntity");
foreach (Type t in typeof(BaseEntity).Assembly.GetTypes().Where(x => x.IsSubclassOf(typeof(BaseEntity))))
{
var configurator = entityMethod.MakeGenericMethod(t).Invoke(modelBuilder, new object[0]);
configurationMethod.MakeGenericMethod(t).Invoke(null, new object[1] { configurator });
}
However, if it was my code, I'd prefer to write one line of code per entity class instead of going for the dynamic discovery.
Upvotes: 2