如何在 entity framework 中处理抽象基础 class(代码优先)?
How to to handle abstract base class in entity framework(code first)?
我正在实施审计功能以跟踪对任何类型的对象所做的任何更改(创建、更新、删除)。为此,我需要一种方法来声明一个通用对象,该对象可以指向从抽象基 class.
派生的任何其他 class 的对象
Base class 我不想在数据库中使用 table :
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);
// ...
}
当我尝试为审核创建迁移时 class,出现以下错误
The derived type 'Audit' cannot have KeyAttribute on property
'AuditId' since primary key can only be declared on the root type.
如果需要,这是我的数据库上下文
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 的 public DateTime CreationDateTime 属性中删除 [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 属性。
我也会删除
public EntityBase Entity { get; set; }
来自审计 class ,您将无法使用它。或者你可以尝试让它不被映射
[NotMapped]
public EntityBase Entity { get; set; }
通过Entity
属性 in Audit
,EF在实现模型上采取了完全不同的路径。
没有它,它会将每个实体映射到其自己独立的 table,每个 table 具有所有列,包括 EntityBase
中的列。事实上,它完全忽略了EntityBase
。至于EF,没有继承。
如果存在,EF 会识别出 Audit
需要从 EntityBase
派生的 any 类型的外键。为了实现这个多态关联,需要一个基础table来“收集”EntityBase
实体的所有主键值。 Audit
指的是这个基 table 的主键。
此外,table EntityBase
包含所有共享属性(CreationDateTime
等),而单独的实体 table 只有自己的属性 and 也是 EntityBase
的外键的主键。这被称为 Table 每个类型 (TPT) 继承。
此 TPT 继承还要求 EntityBase
具有主键 属性,这意味着继承实体不应该。
总而言之,如果您从继承实体中删除关键属性并添加
public int ID { get; set; }
到 EntityBase
,EF 将能够映射您的 class 模型。
但是,请注意 ins and outs of TPT inheritance,尤其是。警告
In many cases, TPT shows inferior performance when compared to TPH.
当然,与没有继承相比,更是如此。
我正在实施审计功能以跟踪对任何类型的对象所做的任何更改(创建、更新、删除)。为此,我需要一种方法来声明一个通用对象,该对象可以指向从抽象基 class.
派生的任何其他 class 的对象Base class 我不想在数据库中使用 table :
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);
// ...
}
当我尝试为审核创建迁移时 class,出现以下错误
The derived type 'Audit' cannot have KeyAttribute on property 'AuditId' since primary key can only be declared on the root type.
如果需要,这是我的数据库上下文
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 的 public DateTime CreationDateTime 属性中删除 [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 属性。
我也会删除
public EntityBase Entity { get; set; }
来自审计 class ,您将无法使用它。或者你可以尝试让它不被映射
[NotMapped]
public EntityBase Entity { get; set; }
通过Entity
属性 in Audit
,EF在实现模型上采取了完全不同的路径。
没有它,它会将每个实体映射到其自己独立的 table,每个 table 具有所有列,包括
EntityBase
中的列。事实上,它完全忽略了EntityBase
。至于EF,没有继承。如果存在,EF 会识别出
Audit
需要从EntityBase
派生的 any 类型的外键。为了实现这个多态关联,需要一个基础table来“收集”EntityBase
实体的所有主键值。Audit
指的是这个基 table 的主键。此外,table
EntityBase
包含所有共享属性(CreationDateTime
等),而单独的实体 table 只有自己的属性 and 也是EntityBase
的外键的主键。这被称为 Table 每个类型 (TPT) 继承。
此 TPT 继承还要求 EntityBase
具有主键 属性,这意味着继承实体不应该。
总而言之,如果您从继承实体中删除关键属性并添加
public int ID { get; set; }
到 EntityBase
,EF 将能够映射您的 class 模型。
但是,请注意 ins and outs of TPT inheritance,尤其是。警告
In many cases, TPT shows inferior performance when compared to TPH.
当然,与没有继承相比,更是如此。