使用 EF Core 的影子属性实现通用审计字段





4.00/5 (1投票)
了解如何使用 Entity Framework 的新影子属性功能,轻松为实体实现通用的审计字段
EF Core 最酷的功能之一是你可以定义不存在于 Entity
类中的属性。它们被称为影子属性。在使用 EF6 时,我需要一些每个实体都会扩展的通用审计字段。例如,当表中的某一行被更新时,当某一行被创建时,行的版本是什么等等。由于 EF6 中没有影子属性的概念,我和许多其他开发人员所做的是创建一个包含这些通用字段的接口,并在需要的实体中实现该接口。然后通过更改跟踪添加或更新这些字段的值。就像这样
public interface IAuditable
{
DateTime Created { get; set; }
DateTime Modified { get; set; }
}
在需要时实现接口
public class Person : IAuditable
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public DateTime Created { get; set; }
public DateTime Modified { get; set; }
}
通过实体更改跟踪更新审计字段的值
public override int SaveChanges()
{
foreach (var auditableEntity in ChangeTracker.Entries<IAuditable>())
{
if (auditableEntity.State == EntityState.Added ||
auditableEntity.State == EntityState.Modified)
{
auditableEntity.Entity.Modified = DateTime.Now;
if (auditableEntity.State == EntityState.Added)
{
auditableEntity.Entity.Created = DateTime.Now;
}
}
}
return base.SaveChanges();
}
与其创建一个接口并在每个实体中实现它,我们还可以将审计字段添加为影子字段。这只是另一种方式,不是首选方式。因此,在设计实体时要非常谨慎。
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<Person>().Property<DateTime?>("Created");
builder.Entity<Person>().Property<DateTime?>("Modified");
}
这里,数据类型后的问号表示数据库中映射的列类型可以为
null
值。 如果你没有指定,对于datetime
列类型,ef core 会设置一个默认的datetime 字符串
,有时可能会让人困惑。
由于影子属性不是具体实体的一部分,因此访问它们及其处理值的方式与通常的方式大不相同。
public override int SaveChanges()
{
var modifiedEntries = ChangeTracker.Entries()
.Where(e => e.State == EntityState.Added || e.State == EntityState.Modified);
foreach (EntityEntry entry in modifiedEntries)
{
var entityType = entry.Context.Model.FindEntityType(entry.Entity.GetType());
var modifiedProperty = entityType.FindProperty("Modified");
var createdProperty = entityType.FindProperty("Created");
if (entry.State == EntityState.Modified && modifiedProperty != null)
{
entry.Property("Modified").CurrentValue = DateTime.Now;
}
if (entry.State == EntityState.Added && createdProperty != null)
{
entry.Property("Created").CurrentValue = DateTime.Now;
}
}
return base.SaveChanges();
}
就这样!这就是你使用影子属性以不同的方式为实体实现审计字段的方法。但使用它们与否由你决定。