1

I have database objects that all inherit from a parent class with some base properties.

Base Entity

public abstract class Entity : IAuditable
{
    public int Id { get; set; }
    public string CreatedBy { get; set; }
    public int? CreatedDate { get; set; }
    public string UpdateBy { get; set; }
    public int? UpdatedDate { get; set; }
}

Base Entity Configuration file

public EntityConfiguration()
{
    HasKey(e => e.Id);

    Property(e => e.Id)
        .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

    Property(e => e.CreatedBy)
        .IsUnicode(false)
        .HasMaxLength(255);

    Property(e => e.UpdatedBy)
        .IsUnicode(false)
        .HasMaxLength(255);
}

I subclass entity on all the child classes to inherit the common properties

public class User : Entity
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

DbContext

public class SomeContext : DbContext
{
    public SomeContext() : base("name=DefaultConnection")
    {
    }

    public static SomeContext Create()
    {
        return new SomeContext();
    }

    public DbSet<Collaboration> Users { get; set; }

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

When I create the migrations It will create all the inherited properties correctly but it still creates the parent class (Entity) even though I don't have a DbSet. If I remove the line that adds the configuration settings in the OnModelCreating method I don't get the max lengths and Unicode settings.

Is there a way to use the configuration properties without actually creating the parent table and without adding the configurations to all the subclass configuration files.

3 Answers 3

1

This approach of inheritance with EF Code first is the Table per Concrete Type TPC Hierarchy

In the link you can find all the logic with examples on how to implement it. I know I shouldn't provide links but check the link, it has everything :)

Examples, Code explanation, graphs and images. I think it is exactly what you need to understand the TPC.

Sign up to request clarification or add additional context in comments.

1 Comment

I did run into this link but it doesn't how me to make the changes in the EntityConfiguration class. I ended up using modelBuilder.Types<Entity>().Configure(c => {}) to fix my issue. I will post the answer as soon as the two day grace period is over.
-1

If anyone is interested here are the two solutions that I came up with. I opted for the second one as it seems to be the more accurate solution.

Solution 1

Use the Types configuration to the base class and anything inheriting the base class will also inherit the configuration.

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Types<Entity>().Configure(c =>
    {
        c.HasKey(e => e.Id);

        c.Property(e => e.Id)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

        c.Property(e => e.CreatedBy)
            .IsUnicode(false)
            .HasMaxLength(255);

        c.Property(e => e.UpdatedBy)
            .IsUnicode(false)
            .HasMaxLength(255);
    });

    modelBuilder.Configurations.Add(new UserConfiguration());
} 

Solution 2

Use a combination of Generics, Interfaces and Inheritance to create a base EntityTypeConfiguration class. Then have other entity type configurations classes inherit from it.

public interface IEntity
{
    int Id { get; set; }
}

public interface IAuditable
{
    string CreatedBy { get; set; }
    DateTime? CreatedDate { get; set; }
    string UpdatedBy { get; set; }
    DateTime? UpdatedDate { get; set; }
}

public class EntityConfiguration<T> : EntityTypeConfiguration<T> where T : class, IEntity, IAuditable
{
    public EntityConfiguration()
    {
        HasKey(e => e.Id);

        Property(e => e.Id)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

        Property(e => e.CreatedBy)
            .IsUnicode(false)
            .HasMaxLength(255);

        Property(e => e.UpdatedBy)
            .IsUnicode(false)
            .HasMaxLength(255);
    }
}

Comments

-1

First remove your Base EntityConfiguration class as you don't want to generate database table for it

Solution-1: Using Data Annotation

Your Base Entity class should be as follows:

public abstract class Entity
{
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }

        [MaxLength(255)]
        [Column(TypeName = "Varchar")]
        public string CreatedBy { get; set; }

        public DateTime? CreatedDate { get; set; }

        [MaxLength(255)]
        [Column(TypeName = "Varchar")]
        public string UpdateBy { get; set; }

        public DateTime? UpdatedDate { get; set; }
 }

and then your DbContext should be as follows:

public class SomeContext : DbContext
{
    public SomeContext() : base("name=DefaultConnection")
    {
    }

    public static SomeContext Create()
    {
        return new SomeContext();
    }

    public DbSet<User> Users { get; set; }

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

}

Solution-2: Using Fluent API

Your Base Entity configuration in the DbContext should be as follows:

public class SomeContext : DbContext
{
    public SomeContext() : base("name=DefaultConnection")
    {
    }

    public static SomeContext Create()
    {
        return new SomeContext();
    }

    public DbSet<Collaboration> Users { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
       modelBuilder.Types<Entity>().Configure(c =>
        {
            c.HasKey(e => e.Id);

            c.Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

            c.Property(e => e.CreatedBy)
                .IsUnicode(false)
                .HasMaxLength(255);

            c.Property(e => e.UpdateBy)
                .IsUnicode(false)
                .HasMaxLength(255);
        });
        modelBuilder.Configurations.Add(new UserConfiguration());
    }
}

On both cases Migration will generate Users Table as follows:

public override void Up()
{
            CreateTable(
                "dbo.Users",
                c => new
                    {
                        Id = c.Int(nullable: false, identity: true),
                        FirstName = c.String(),
                        LastName = c.String(),
                        CreatedBy = c.String(maxLength: 255, unicode: false),
                        CreatedDate = c.DateTime(),
                        UpdateBy = c.String(maxLength: 255, unicode: false),
                        UpdatedDate = c.DateTime(),
                    })
                .PrimaryKey(t => t.Id);

  }

Hope your problem will be solved!

11 Comments

I did try this previously. Although it will give me the inherited fiels, I lose the custom field properties such as max length and Unicode that are in the EntityTypeConfiguration class. I do come up with a solution which I will post when the two day grace period is over
@Dblock247 Why would you lose custom field properties? Okay let me check again.
because you are removing modelBuilder.Configurations.Add(new EntityConfiguration()) from OnModelConfiguration. That class contains all the configuration info. Also the point is not to add configuration to each child entity. I want it to inherit everything from the parent
but I am using UserCofiguration..Please read my answer thoroughly..No problem I am checking it with a new project.
Yes I know but if i was going to do that. I dont need inheritance. I would have to add that to every child entity configuration
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.