Configuring abstract base class without creating table in EF Core

c# database-migration entity-framework entity-framework-core migration

Question

I have added DateCreated, UserCreated, DateModified and UserModified fields to each entity by creating a BaseEntity.cs class. My requirement is to generate single table which is having all the fields of base class as columns.

public class BaseEntity
{
     public DateTime? DateCreated { get; set; }
     public string UserCreated { get; set; }
     public DateTime? DateModified { get; set; }
     public string UserModified { get; set; }
}

Here is my Student class

public class Student : BaseEntity
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Here is my context class

public class SchoolContext: DbContext
{       
    public LibraContext(DbContextOptions<SchoolContext> options)
        : base(options)
    { }

    public DbSet<Student> Students { get; set; }
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
        //CreatedDate 
        modelBuilder.Entity<BaseEntity>().Property(x => x.DateCreated).HasDefaultValueSql("GETDATE()");
        //Updated Date
        modelBuilder.Entity<BaseEntity>().Property(x => x.DateModified).HasDefaultValueSql("GETDATE()");
 }

I have run the below migration commands to create script and update database

Add-Migration -Name "InitialMigration" -Context "SchoolContext"
update-database

It has created separate tables BaseEntity and Student in the SQL Server database. My expectation is to create a single Student table with all the BaseEntity fields as columns.

How to achieve it?

I am using ASP.NET CORE2.1

1
3
1/9/2019 7:35:09 AM

Accepted Answer

According to Microsoft Documentation you can use [NotMapped] data annotation or modelBuilder.Ignore<TEntity>(); to ignore the table creation for BaseEntity as follows:

But in your case [NotMapped] would not help you because Fluent API always has higher priority than the data annotations (attributes). So you can call modelBuilder.Ignore<BaseEntity>(); after the BaseEntity configuration in the OnModelCreating but calling modelBuilder.Ignore<BaseEntity>(); will lose the BaseEntity configurations.

So as per as I am concerned the best solution would be as follows:

Write the configuration for BaseEntity as follows:

public class BaseEntityConfigurations<TEntity> : IEntityTypeConfiguration<TEntity> where TEntity : BaseEntity
{
    public virtual void Configure(EntityTypeBuilder<TEntity> builder)
    {
        //CreatedDate 
        builder.Property(x => x.DateCreated).HasDefaultValueSql("GETDATE()");
        //Updated Date
        builder.Property(x => x.DateModified).HasDefaultValueSql("GETDATE()");
    }
}

Then write the configuration for Student as follows:

public class StudentConfigurations : BaseEntityConfigurations<Student>
{
    public override void Configure(EntityTypeBuilder<Student> builder)
    {
        base.Configure(builder); // Must call this

       // other configurations here
    }
}

Then in the OnModelCreating as follows:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
     base.OnModelCreating(modelBuilder);

     modelBuilder.ApplyConfiguration(new StudentConfigurations());
}

Migration will generate the only Student table with BaseEntity configuration as follows:

migrationBuilder.CreateTable(
            name: "Students",
            columns: table => new
            {
                Id = table.Column<int>(nullable: false)
                    .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
                DateCreated = table.Column<DateTime>(nullable: true, defaultValueSql: "GETDATE()"),
                UserCreated = table.Column<string>(nullable: true),
                DateModified = table.Column<DateTime>(nullable: true, defaultValueSql: "GETDATE()"),
                UserModified = table.Column<string>(nullable: true),
                Name = table.Column<string>(nullable: true)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_Students", x => x.Id);
            });
2
1/8/2019 2:39:11 PM

Popular Answer

I have resolved the issue by simple change! We have to use Student entity in modelbuilder. I was mistakenly used BaseEntity

  protected override void OnModelCreating(ModelBuilder modelBuilder)
  {
     modelBuilder.Entity<Student>().Property(x => x.Created).HasDefaultValueSql("GETDATE()");
     modelBuilder.Entity<Student>().Property(x => x.Updated).HasDefaultValueSql("GETDATE()");
  }

Open Issue: The order of generated table columns can not be controlled by order number. This is not currently supported by .net core.



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow