简体   繁体   English

如何在实体框架中处理抽象基础 class(代码优先)?

[英]How to to handle abstract base class in entity framework(code first)?

I am implementing an audit functionality to keep track of any changes (create, update, delete) made to any type of object.我正在实施审计功能,以跟踪对任何类型的 object 所做的任何更改(创建、更新、删除)。 For this I need a way to declare a generic object which can point to object of any other class derived from an abstract base class.为此,我需要一种方法来声明一个通用的 object,它可以指向任何其他 class 的 object,这些 class 派生自抽象基 ZA2F2ED4F8EBC2CABDD4ZC2。

Base class I do not want to have table for in database:基本 class 我不想在数据库中有表:

  public abstract class EntityBase {
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [DataType(DataType.Date)]
    public DateTime CreationDateTime { get; set; }

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    [DataType(DataType.Date)]
    public DateTime ModificationDateTime { get; set; }
  }

  public class EntityBaseConfigurations<TEntity> : IEntityTypeConfiguration<TEntity> where TEntity : EntityBase {
    public virtual void Configure(EntityTypeBuilder<TEntity> builder) {
      builder.Property(e => e.CreationDateTime).IsRequired().HasDefaultValueSql("GETUTCDATE()");
      builder.Property(e => e.ModificationDateTime).IsRequired().HasDefaultValueSql("GETUTCDATE()");
    }
  }

and a couple of models derived from base for example:以及从 base 派生的几个模型,例如:

  [Table("Initiative")]
  public class Initiative : EntityBase {
    [Key]
    public int InitiativeId { get; set; }

    // ...

    [Required]
    public Contributor Assignee { get; set; }
  }

  public class InitiativeConfiguration : EntityBaseConfigurations<Initiative> {
    public override void Configure(EntityTypeBuilder<Initiative> builder) => base.Configure(builder);

    // ...
  }
  [Table("Contributor")]
  public class Contributor : EntityBase {
    [Key]
    public int ContributorId { get; set; }

    // ...
  }

  public class ContributorConfiguration : EntityBaseConfigurations<Contributor> {
    public override void Configure(EntityTypeBuilder<Contributor> builder) => base.Configure(builder);

    // ...
  }

Now my failed attempt to create the Audit model现在我尝试创建审计 model 失败

  [Table("Audit")]
  public class Audit : EntityBase {
    [Key]
    public int AuditId { get; set; }

    public User Actor {get; set;}

    // ...

    public EntityBase Entity { get; set; } // I want to be able to point to objct of any class derived from EntityBase (ex. Initiative, Contributor)
  }

  public class AuditConfiguration : EntityBaseConfigurations<Audit> {
    public override void Configure(EntityTypeBuilder<Audit> builder) => base.Configure(builder);
    // ...
  }

When I try to create a migration for audit class, I get below error当我尝试为审计 class 创建迁移时,出现以下错误

The derived type 'Audit' cannot have KeyAttribute on property 'AuditId' since primary key can only be declared on the root type.派生类型“Audit”不能在属性“AuditId”上具有 KeyAttribute,因为只能在根类型上声明主键。

Here is my Db Context if needed如果需要,这是我的 Db 上下文

  public class DbContext : IdentityDbContext<User> {
    public DbContext(DbContextOptions<DbContext> options) : base(options) { }

    public DbSet<Initiative> Initiatives { get; set; }
    public DbSet<Contributor> Contributors { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder) {
      base.OnModelCreating(modelBuilder);
      modelBuilder.ApplyConfiguration(new InitiativeConfiguration());
      modelBuilder.ApplyConfiguration(new ContributorConfiguration());
    }
  }

try to remove [DatabaseGenerated(DatabaseGeneratedOption.Identity)] attribute from public DateTime CreationDateTime propert of EntityBase.尝试从 EntityBase 的公共 DateTime CreationDateTime 属性中删除 [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 属性。

Also I would remove我也会删除

public EntityBase Entity { get; set; }  

from Audit class, you would not be able to use it.从审核 class,您将无法使用它。 Or you can try to make it not mapped或者您可以尝试使其未映射

[NotMapped]
public EntityBase Entity { get; set; }  

By this Entity property in Audit , EF takes a completely different path in implementing the model.通过Audit中的这个Entity属性,EF 在实现 model 时采用了完全不同的路径。

  • Without it, it maps each entity to its own independent table, each table having all columns including the ones in EntityBase .没有它,它将每个实体映射到自己的独立表,每个表都有所有列,包括EntityBase中的列。 In fact, it completely ignores EntityBase .事实上,它完全忽略了EntityBase As for EF, there is no inheritance.至于EF,没有inheritance。

  • If it's there, EF recognizes that Audit needs a foreign key to any type derived from EntityBase .如果存在,则 EF 会识别Audit需要从EntityBase派生的任何类型的外键。 In order to implement this polymorphic association , a base table is required that "collects" all primary key values of EntityBase entities.为了实现这种多态关联,需要一个“收集” EntityBase实体的所有主键值的基表。 Audit refers to this base table's primary key. Audit引用此基表的主键。

    Also, table EntityBase contains all shared properties ( CreationDateTime etc), and the separate entity table only have their own properties and a primary key that's also a foreign key to EntityBase .此外,表EntityBase包含所有共享属性( CreationDateTime等),并且单独的实体表只有它们自己的属性一个主键,它也是EntityBase的外键。 This is referred to as Table per Type (TPT) inheritance.这称为按类型表(TPT) inheritance。

This TPT inheritance also requires EntityBase to have the primary key property, implying that the inheriting entities shouldn't.此 TPT inheritance 还要求EntityBase具有主键属性,这意味着继承实体不应该。

All in all, if you remove the key properties from the inheriting entities and add总而言之,如果您从继承实体中删除关键属性并添加

public int ID { get; set; }

to EntityBase , EF will be able to map your class model.EntityBase ,EF 将能够 map 你的 class model。

However, be aware of the ins and outs of TPT inheritance , esp.但是,请注意TPT inheritance 的来龙去脉,尤其是。 the warning警告

In many cases, TPT shows inferior performance when compared to TPH.在许多情况下,与 TPH 相比,TPT 的性能较差。

And, of course, more so compared to no inheritance.当然,与没有 inheritance 相比,更是如此。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何忽略实体框架中的非抽象基类? - How to ignore a not abstract base class in Entity Framework? 如何首先使此基类与Entity Framework 6.1代码一起使用 - How to make this base class work with Entity Framework 6.1 code first 实体框架代码优先-没有主键的抽象模型类 - Entity Framework Code First - Abstract model class without primary key 实体框架代码优先-派生类与基类不在同一程序集中 - Entity Framework code first - Derived class not in the same assembly as the base class 首先完全忽略实体框架5代码中的基类/接口 - Ignore base class / interfaces completely in entity framework 5 code first 实体框架代码优先-对象全部继承基类,如何排除具有禁用属性的记录 - Entity Framework Code First - objects all inherit base class, how to exclude records with a disabled property 如何最好地手动使用Entity Framework Code First模型类处理现有数据库列映射? - How best to handle existing database column mappings with an Entity Framework Code First model class manually? 如何首先使用实体​​代码和状态模式映射抽象类 - How to map abstract class using entity code first and State Pattern 如何在Entity Framework代码优先中处理自我引用? - How to handle self references in Entity Framework code-first? 如何处理实体框架中的主键5代码优先 - How to Handle Primary Key in Entity Framework 5 Code First
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM