【问题标题】:How do I create composite key which is combination of base class and derived class in Entity Framework Core如何在 Entity Framework Core 中创建组合键,它是基类和派生类的组合
【发布时间】:2019-06-01 04:39:21
【问题描述】:

我需要在实体框架中创建复合键。

我的基类键是“Guid”,我希望学生类中有一些独特的东西,比如可以读取的“ID”。像“STUD01”,它确实需要可读的唯一数据。

[NotMapped]
public class BaseEntity
{
     public Guid Key { get; set; }
     public DateTime? DateCreated { get; set; }
     public string UserCreated { get; set; }
     public DateTime? DateModified { get; set; }
     public string UserModified { get; set; }
}

这是我的Student 课程

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

这是我的上下文类

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

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

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

     //here is my composite key
     modelBuilder.Entity<Student>().HasKey(c => new { c.Key, c.Id });
 }

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

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

我得到这个错误:

无法在“学生”上配置密钥,因为它是派生类型。必须在根类型“BaseClass”上配置密钥。如果您不打算将“BaseClass”包含在模型中,请确保它不包含在上下文的 DbSet 属性中、在对 ModelBuilder 的配置调用中引用或从包含的类型的导航属性中引用在模型中。

如何实现?

我正在使用 ASP.NET Core 2.1

【问题讨论】:

  • modelBuilder.Entity 调用意味着将有一个名为 BaseTable 的表,必须在其上定义所有关键属性。您可能的意思是调用 modelBuilder.Types API。

标签: c# entity-framework asp.net-core migration


【解决方案1】:

问题是[Not Mapped] 数据注解没有忽略表的创建,因为Fluent API 总是比数据注解(属性)具有更高的优先级。所以你可以在OnModelCreating 中的BaseEntity 配置之后调用modelBuilder.Ignore&lt;BaseEntity&gt;();,但调用modelBuilder.Ignore&lt;BaseEntity&gt;(); 将丢失BaseEntity 配置。

所以最好的解决方案是:

BaseEntity编写配置如下:

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

然后为Student编写配置如下:

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

       // composite key
        builder.HasKey(c => new { c.Key, c.Id });
    }
}

然后在OnModelCreating中如下:

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

     modelBuilder.ApplyConfiguration(new StudentConfigurations());
}

现在一切正常!

注意:如果您已经有一个数据库,那么它不适用于迁移。您必须通过初始迁移生成全新的表,因为 Entity Framework 核心无法通过迁移更改主键。

【讨论】:

  • @kudlatiger 我已经更新了我的答案!请检查一下!现在应该可以解决问题了。
  • @kudlatiger 但是有一个小问题。我再次更新这个答案。并遵循更新的版本。这将为您提供完整的证明解决方案。
  • 是的,那么我认为这个问题值得 +1 :)。让我修改并测试一下。
  • 为什么BaseEntityConfigurations中没有“builder.Property”?
  • BaseEntityConfigurations&lt;TEntity&gt; 中使用过这个where TEntity : BaseEntity。彻底复制我的代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-06
  • 1970-01-01
  • 2020-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多