我正在實施審計功能來跟蹤對任何型別的物件所做的任何更改(創建、更新、洗掉)。為此,我需要一種方法來宣告一個泛型物件,該物件可以指向從抽象基類派生的任何其他類的物件。
我不想在資料庫中有表的基類:
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);
// ...
}
現在我嘗試創建審計模型失敗
[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);
// ...
}
當我嘗試為審計類創建遷移時,出現以下錯誤
派生型別“Audit”不能在屬性“AuditId”上具有 KeyAttribute,因為只能在根型別上宣告主鍵。
如果需要,這是我的資料庫背景關系
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());
}
}
uj5u.com熱心網友回復:
嘗試從 EntityBase 的公共 DateTime CreationDateTime 屬性中洗掉 [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 屬性。
我也會洗掉
public EntityBase Entity { get; set; }
從 Audit 類,您將無法使用它。或者你可以嘗試讓它不被映射
[NotMapped]
public EntityBase Entity { get; set; }
uj5u.com熱心網友回復:
通過 中的這個Entity屬性Audit,EF 在實作模型時采用了完全不同的路徑。
沒有它,它會將每個物體映射到自己獨立的表,每個表都包含所有列,包括 中的列
EntityBase。事實上,它完全忽略了EntityBase. 至于EF,沒有繼承。如果它的存在,EF認識到
Audit需要一個外鍵的任何衍生型EntityBase。為了實作這種多型關聯,需要一個“收集”EntityBase物體的所有主鍵值的基表。Audit指的是這個基表的主鍵。此外,表
EntityBase包含所有共享屬性(CreationDateTime等),而單獨的物體表只有自己的屬性和一個主鍵,該主鍵也是EntityBase. 這稱為按型別表(TPT) 繼承。
此 TPT 繼承還需要EntityBase具有主鍵屬性,這意味著繼承物體不應該。
總而言之,如果您從繼承物體中洗掉關鍵屬性并添加
public int ID { get; set; }
到EntityBase,EF 將能夠映射您的類模型。
但是,請注意TPT 繼承的來龍去脈,尤其是。警告
在許多情況下,與 TPH 相比,TPT 表現出較差的性能。
而且,當然,與沒有繼承相比更是如此。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/396908.html
標籤:C# 遗产 实体框架核心 asp.net-core-webapi
上一篇:單擊表單時頁面重定向
