每次在数据库中更改一行时,它都需要将该行的所有列值连同作者和日期戳一起写入审计表。
我以前做过这个确切的事情,但没有涉及到继承关系(另一次是数据库优先,所以维护两个具有几乎所有相同属性的单独类并不是那么烦人,因为 EF 设计者正在这样做我...)
给定 SQL Server 中的以下表结构:
CREATE TABLE SampleClass
(
Id int NOT NULL IDENTITY PRIMARY KEY,
ImagineABunchOfColumnsHere int
)
CREATE TABLE Audit_SampleClass
(
AuditId bigint NOT NULL IDENTITY PRIMARY KEY,
ChangedOn datetime NOT NULL,
ChangedBy nvarchar(200) NOT NULL,
ChangeType nvarchar(200) NOT NULL,
Id int NOT NULL,
ImagineABunchOfColumnsHere int
)
以及 C# 中的以下类:
public class SampleClass
{
public int Id { get; set; }
public int ImagineABunchOfColumnsHere { get; set; }
}
public class Audit_SampleClass : SampleClass
{
public int64 AuditId { get; set; }
public DateTime ChangedOn { get; set; }
public string ChangedBy { get; set; }
public string ChangeType { get; set; }
}
public class SampleContext : DbContext
{
public virtual DbSet<SampleClass> SampleClasses { get; set; }
public vidtual DbSet<Audit_SampleClass> Audit_SampleClasses { get; set; }
public override int SaveChanges()
{
// There's code here that does the following (normally in a transaction)
// 1) Set aside a local copy of this.ChangeTracker.Entries() to use later
// 2) Call base.SaveChanges()
// 3) For each change, add a row to the corresponding audit table
// 4) Call base.SaveChanges() again
}
}
我无法让 Entity Framework 以这种方式工作。
EF 继承策略的所有信息和示例都假设您有一个抽象类和两个从它继承的具体类。似乎没有人在我想要直接继承 TPT/TPC 的这条船上……
我尝试过的各种组合都会导致以下一个或多个问题:
- 将 1 个新对象插入 SomeClasses DbSet 时,而不是 SomeClasses 表中的 1 个新行和 Audit_SomeClasses 表中的 1 个新行具有相同的 ImagineABunchOfColumns here 值,我在 SomeClasses 表中得到两个相同的行和 Audit_SomeClasses 中的 1 个新行具有NULL ImagineABunchOfColumns 的表。或者,
- 第一个 SaveChanges() 因“当 IDENTITY_INSERT 设置为 OFF 时无法在表 'SampleClass' 中插入标识列的显式值”而崩溃。和/或,
- 第二个 SaveChanges() 调用因“当 IDENTITY_INSERT 设置为 OFF 时无法在表 'Audit_SampleClass' 中插入标识列的显式值”而崩溃。和/或,
- 尝试从任一 DbSet 中选择会崩溃,并显示“EntitySet 'SampleContext.SampleClasses' 中的所有对象必须具有唯一的主键。但是,'SampleClass' 类型的实例和 'Audit_SampleClass' 类型的实例都具有相同的主键值, 'EntitySet=SampleClasses;Id=[whatever]'。”
基本上我似乎找不到任何 EntityTypeConfiguration 组合使 EF 完全分开处理这两个类;它要么会复制事物,因为它以某种方式执行向后 TPH,要么会将 Audit_SampleClass 上继承的 Id 属性视为主键,即使它不在该类上(我知道某些继承类型存在唯一性问题,但它是甚至没有冲突的键,它是一把钥匙和一把不应该成为钥匙的钥匙),或者它会拒绝将一个或两个钥匙视为身份......
我不希望代码生成能够处理这种情况,但是当引入我自己的类并在它们上显式配置 ToTable 和 HasKey 和 MapInheritedProperties 时,肯定有一种方法可以让它分别处理这两个类而不干扰彼此?
编辑:
根据评论中的要求,这里是映射类。取消注释的注释行的各种组合会导致上面的项目符号中列出的不同结果。
public class SampleClassMap : EntityTypeConfiguration<SampleClass>
{
public SampleClassMap()
{
this.ToTable("SampleClass");
this.HasKey(s => s.Id);
// this.Property(s => s.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
public class Audit_SampleClassMap : EntityTypeConfiguration<Audit_SampleClass>
{
public Audit_SampleClassMap()
{
this.ToTable("Audit_SampleClass");
this.HasKey(a => a.AuditId);
this.Property(a => a.AuditId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
// this.Map(a => a.MapInheritedProperties());
}
}