5

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".

blgrnboy
  • 4,877
  • 10
  • 43
  • 94
  • 1
    Why are you setting the key explicitly? EF infers attributes with name `Id` or `classname+Id` to be keys anyway. – venerik Oct 01 '15 at 21:49
  • That's a fair point, the key doesn't have to be set explicitly, so it probably was a bad example. However, there are other properties that have to be mapped, or ignored, that may have specifics tied to them, such as IsOptional, IsRequired, and/or HasMaxLength. – blgrnboy Oct 01 '15 at 21:57

1 Answers1

6

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);
...
blgrnboy
  • 4,877
  • 10
  • 43
  • 94