配置抽象基类而不在 EF Core 中创建表

kud*_*ger 6 c# migration entity-framework database-migration entity-framework-core

我已经加入DateCreatedUserCreatedDateModifiedUserModified通过创建一个字段每个实体BaseEntity.cs类。我的要求是生成单个表,该表将base类的所有字段作为列。

public class BaseEntity
{
     public DateTime? DateCreated { get; set; }
     public string UserCreated { get; set; }
     public DateTime? DateModified { get; set; }
     public string UserModified { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这是我的Student

public class Student : BaseEntity
{
    public int Id { get; set; }
    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这是我的上下文类

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()");
 }
Run Code Online (Sandbox Code Playgroud)

我已经运行以下迁移命令来创建脚本和更新数据库

Add-Migration -Name "InitialMigration" -Context "SchoolContext"
update-database
Run Code Online (Sandbox Code Playgroud)

它创造了单独的表BaseEntity,并Student在SQL Server数据库。我的期望是创建一个Student将所有BaseEntity字段作为列的表。

如何实现?

我正在使用 ASP.NET CORE2.1

Tan*_*jel 8

根据Microsoft 文档,您可以使用[NotMapped] 数据注释或modelBuilder.Ignore<TEntity>();忽略表创建,BaseEntity如下所示:

但在你的情况下[NotMapped]不会帮助你,因为Fluent API总是比数据注释(属性)具有更高的优先级。所以你可以modelBuilder.Ignore<BaseEntity>();BaseEntity配置后OnModelCreating调用,但是调用modelBuilder.Ignore<BaseEntity>();会丢失BaseEntity配置。

因此,据我所知,最佳解决方案如下:

编写BaseEntity如下配置:

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()");
    }
}
Run Code Online (Sandbox Code Playgroud)

然后编写Student如下配置:

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

       // other configurations here
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在OnModelCreating如下:

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

     modelBuilder.ApplyConfiguration(new StudentConfigurations());
}
Run Code Online (Sandbox Code Playgroud)

迁移将生成唯一Student具有BaseEntity如下配置的表:

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);
            });
Run Code Online (Sandbox Code Playgroud)

  • 这消除了错误,但现在属性设置(`DefaultValueSql` 等)丢失(不包含在生成的迁移代码中)。所以不幸的是,hack 不起作用。处理这种情况的正确方法显示在重复链接和其他一些类似的帖子中,这些帖子迭代了 `modelBuilder.Model.GetEntityTypes()` 并为所有派生的实体类型调用了一些通用配置代码。这种情况下的基类永远不应该被指定为实体,也不能为所有派生实体配置一次其属性。 (2认同)