phil soady
phil soady

Reputation: 11348

Abstract domain model base class when using EntityTypeConfiguration<T>

Is there some trick to getting a central mapping of Base object properties? Is there some simple pattern for abstract classes when using EntityTypeConfiguration.
ANy tips much appreciated. Im unable to declare a class

Public class BaseEntityConfig<T> : EntityTypeConfiguration<T>

Similar issues, where i couldnt get the answers to work How to create and use a generic class EntityTypeConfiguration<TEntity> and Dynamic way to Generate EntityTypeConfiguration : The type 'TResult' must be a non-nullable value type

public  abstract class BosBaseObject
{
  public virtual Guid Id { set; get; }
  public virtual string ExternalKey { set; get; }
  public byte[] RowVersion { get; set; }
}
  public class News : BosBaseObject
{
    public String Heading { set; get; }
}


public class NewsMap : EntityTypeConfiguration<News>
{
    public NewsMap()
    {
      //Base Object Common Mappings
      // How can we use a central mapping for all Base Abstract properties  


     }
 }
// Something like this but very open to any suggestion....
public class BosBaseEntityConfig<T> : EntityTypeConfiguration<T>
{
  public void BaseObjectMap( )
    { 
        // Primary Key
        this.HasKey(t => t.Id);

        // Properties
        this.Property(t => t.Id).HasDatabaseGeneratedOption(databaseGeneratedOption: DatabaseGeneratedOption.None);

        this.Property(t => t.RowVersion)
            .IsRequired()
            .IsFixedLength()
            .HasMaxLength(8)
            .IsRowVersion();

        //Column Mappings
        this.Property(t => t.Id).HasColumnName("Id");
    }
}

Upvotes: 6

Views: 5158

Answers (4)

skipper_dev
skipper_dev

Reputation: 181

public class BaseEntityTypeConfiguration<T> : IEntityTypeConfiguration<T> where T : BaseEntity
{
    public virtual void Configure(EntityTypeBuilder<T> entity)
    {
        entity.HasKey(e => e.Id);
    }
}


public class NewsEntityTypeConfiguration : BaseEntityTypeConfiguration<News>
{
    public override void Configure(EntityTypeBuilder<News> entity)
    {
        base.Configure(entity);
        entity.ToTable("News");
    }
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.ApplyConfiguration(new NewsEntityTypeConfiguration());
}

Upvotes: 0

user551445
user551445

Reputation: 25

Sorry I cannot comment but I would do as you are doing only swap these two lines around

      modelBuilder.Configurations.Add( conf );  // this has base mapping now
      var newsConf = new NewsConfiguration(conf); // now the Object specific properties stuff
   to
       new NewsConfiguration(conf); // now the Object 
       modelBuilder.Configurations.Add( conf );  // this has base mapping now

This helps EF with specialised fields.

Upvotes: 0

Mac
Mac

Reputation: 330

The answer above definitely works, though this may be slight cleaner and has the advantage of working the same when registering the configurations in the DbContext.

public abstract class BaseEntity
{
    public int Id { get; set; }
}

public class Company : BaseEntity
{
    public string Name { get; set; }
}

internal class BaseEntityMap<T> : EntityTypeConfiguration<T> where T : BaseEntity
{
    public BaseEntityMap()
    {
        // Primary Key
        HasKey(t => t.Id);
    }
}

internal class CompanyMap : BaseEntityMap<Company>
{
    public CompanyMap()
    {
        // Properties
        Property(t => t.Name)
            .IsRequired()
            .HasMaxLength(256);
    }
}

public class AcmeContext : DbContext
{
    public DbSet<Company> Companies { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new CompanyMap());
    }
}

Above solution arrived at by Christian Williams and myself early one morning...

Upvotes: 9

phil soady
phil soady

Reputation: 11348

After 6 hrs I cracked it. I think it is a reasonably clean outcome. The trick is to forget doing every inside a class derived from EntityTypeConfiguration and build a custom BaseConfig and then to take this instance and add the specifics for this class. Hope it helps others doing code first with abstracts...

public  abstract class BosBaseObject
{
  public virtual Guid Id { set; get; }
  public virtual string ExternalKey { set; get; }
  public byte[] RowVersion { get; set; }
}
 public abstract class BosObjectDateManaged   :  BosBaseObject
{
    public DateTimeOffset ValidFrom { set; get; }
    public DateTimeOffset ValidTo { set; get; }
}
public class News : BosObjectDateManaged
{
    public String Heading { set; get; }
}



protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        var conf = new BosBaseEntityConfiguration<News>();//Construct config for Type
        modelBuilder.Configurations.Add( conf );  // this has base mapping now
        var newsConf = new NewsConfiguration(conf); // now the Object specific properties stuff

    }

}
public class BosBaseEntityConfiguration<T> : EntityTypeConfiguration<T> where T : BosBaseObject
{
   public BosBaseEntityConfiguration()
   {
       // Primary Key
       this.HasKey(t => t.Id);

       //// Properties
       this.Property(t => t.Id).HasDatabaseGeneratedOption(databaseGeneratedOption: DatabaseGeneratedOption.None);

       this.Property(t => t.RowVersion)
           .IsRequired()
           .IsFixedLength()
           .HasMaxLength(8)
           .IsRowVersion();

       //Column Mappings
       this.Property(t => t.Id).HasColumnName("Id");
   }
}
 public class NewsConfiguration  
{
    public  NewsConfiguration(BosBaseEntityConfiguration<News> entity)
    {
        // Table Specific & Column Mappings
        entity.ToTable("News2");
        entity.Property(t => t.Heading).HasColumnName("Heading2");
    }
}

Upvotes: 3

Related Questions