[英]How to to handle abstract base class in entity framework(code first)?
我正在實施審計功能,以跟蹤對任何類型的 object 所做的任何更改(創建、更新、刪除)。 為此,我需要一種方法來聲明一個通用的 object,它可以指向任何其他 class 的 object,這些 class 派生自抽象基 ZA2F2ED4F8EBC2CABDD4ZC2。
基本 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()");
}
}
以及從 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);
// ...
}
現在我嘗試創建審計 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);
// ...
}
當我嘗試為審計 class 創建遷移時,出現以下錯誤
派生類型“Audit”不能在屬性“AuditId”上具有 KeyAttribute,因為只能在根類型上聲明主鍵。
如果需要,這是我的 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());
}
}
嘗試從 EntityBase 的公共 DateTime CreationDateTime 屬性中刪除 [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 屬性。
我也會刪除
public EntityBase Entity { get; set; }
從審核 class,您將無法使用它。 或者您可以嘗試使其未映射
[NotMapped]
public EntityBase Entity { get; set; }
通過Audit
中的這個Entity
屬性,EF 在實現 model 時采用了完全不同的路徑。
沒有它,它將每個實體映射到自己的獨立表,每個表都有所有列,包括EntityBase
中的列。 事實上,它完全忽略了EntityBase
。 至於EF,沒有inheritance。
如果存在,則 EF 會識別Audit
需要從EntityBase
派生的任何類型的外鍵。 為了實現這種多態關聯,需要一個“收集” EntityBase
實體的所有主鍵值的基表。 Audit
引用此基表的主鍵。
此外,表EntityBase
包含所有共享屬性( CreationDateTime
等),並且單獨的實體表只有它們自己的屬性和一個主鍵,它也是EntityBase
的外鍵。 這稱為按類型表(TPT) inheritance。
此 TPT inheritance 還要求EntityBase
具有主鍵屬性,這意味着繼承實體不應該。
總而言之,如果您從繼承實體中刪除關鍵屬性並添加
public int ID { get; set; }
到EntityBase
,EF 將能夠 map 你的 class model。
但是,請注意TPT inheritance 的來龍去脈,尤其是。 警告
在許多情況下,與 TPH 相比,TPT 的性能較差。
當然,與沒有 inheritance 相比,更是如此。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.