Entity Framework Core生成列并跟踪列记录
作者:Sweet-Tang 发布时间:2023-07-01 07:06:46
注意:我使用的是 Entity Framework Core 2.0 (2.0.0-preview2-final)。正式版发布时,功能可能存在变动。
当您设计数据库时,有时需要添加列以跟踪记录何时更改,以及谁进行了更改。例如,您添加以下列:
CreatedAt
CreatedBy
LastUpdatedAt
LastUpdatedBy
您可以轻松地使用默认值和触发器来处理CreatedAt
和LastUpdatedAt
列。老实说,创建触发器是件无聊的事情,你也不想自己做。此外,很难设置用户名,因为它是应用程序的信息;实际上,在Web程序的上下文中,它们只是连接到数据库的一个用户,因此,您无法使用数据库中CURRENT_USER
函数设置跟踪列的值。
当然,您不想访问这个属性。相反,您希望 Entity Framework 为您自动执行,所以,解决的办法是调用SaveChanges
或SaveChangesAsync
方法之前自动设置这些属性的值。在模型中有多种方法处理这些属性:您可以在模型中添加读写(R/W)属性;您也可以使用只读(R/O)属性;还有一种方案,您可以使用阴影(Shadow)属性。在最后一种方案中,是将列不映射到模型中的属性,只有 Entity Framework 才知道这些属性。是的,EF Core 非常灵活:)
我们用 Entity Framework 实现这3种方案!
读写属性
在这种情况下,实体将具有读/写属性。这意味着,您可以在代码中更改属性的值。
public interface ITrackable
{
DateTime CreatedAt { get; set; }
string CreatedBy { get; set; }
DateTime LastUpdatedAt { get; set; }
string LastUpdatedBy { get; set; }
}
public class Post : ITrackable
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public DateTime CreatedAt { get; set; }
public string CreatedBy { get; set; }
public DateTime LastUpdatedAt { get; set; }
public string LastUpdatedBy { get; set; }
}
现在,我们将更改SaveChanges
方法的默认行为来设置跟踪属性的值。要小心,有两个方法要重写:SaveChanges
和异步方法SaveChangesAsync
。在代码中遍历上下文中跟踪的实体,并根据状态设置跟踪属性的值。代码非常简单:
public class BloggingContext : DbContext
{
public DbSet<Post> Posts { get; set; }
public override int SaveChanges(bool acceptAllChangesOnSuccess)
{
OnBeforeSaving();
return base.SaveChanges(acceptAllChangesOnSuccess);
}
public override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default(CancellationToken))
{
OnBeforeSaving();
return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}
private void OnBeforeSaving()
{
var entries = ChangeTracker.Entries();
foreach (var entry in entries)
{
if (entry.Entity is ITrackable trackable)
{
var now = DateTime.UtcNow;
var user = GetCurrentUser();
switch (entry.State)
{
case EntityState.Modified:
trackable.LastUpdatedAt = now;
trackable.LastUpdatedBy = user;
break;
case EntityState.Added:
trackable.CreatedAt = now;
trackable.CreatedAt = user;
trackable.LastUpdatedAt = now;
trackable.LastUpdatedBy = user;
break;
}
}
}
}
private string GetCurrentUser()
{
return "UserName"; // TODO implement your own logic
}
}
这个方案有个不容忽视的问题,属性是可写的,您不希望在代码中设置属性的值。让我们看看如何使用只读属性。
只读属性
Entity Framework Core 允许将列映射到字段。这样,您可以使用只读属性,我们来修改 Post
类:
public class Post
{
private DateTime _createdAt;
private string _createdBy;
private DateTime _lastUpdatedAt;
private string _lastUpdatedBy;
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public DateTime CreatedAt => _createdAt;
public string CreatedBy => _createdBy;
public DateTime LastUpdatedAt => _lastUpdatedAt;
public string LastUpdatedBy => _lastUpdatedBy;
}
上面的代码有点麻烦,但属性现在是只读的。您需要指引 Entity Framework 使用这些字段来设置列的值。
public class BloggingContext : DbContext
{
public DbSet<Post> Posts { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Post>()
.Property(post => post.CreatedAt)
.HasField("_createdAt");
modelBuilder.Entity<Post>()
.Property(post => post.CreatedBy)
.HasField("_createdBy");
modelBuilder.Entity<Post>()
.Property(post => post.LastUpdatedAt)
.HasField("_lastUpdatedAt");
modelBuilder.Entity<Post>()
.Property(post => post.LastUpdatedBy)
.HasField("_lastUpdatedBy");
}
}
您不能像以前那样实现OnBeforeSaving
方法,因为属性没有setter
。不过,您可以使用 ChangeTracker
来指引 Entity Framework 为属性设置值。这种方式无需访问属性或字段。
private void OnBeforeSaving()
{
var entries = ChangeTracker.Entries();
foreach (var entry in entries)
{
if (entry.Entity is Post post)
{
var now = DateTime.UtcNow;
var user = GetCurrentUser();
switch (entry.State)
{
case EntityState.Modified:
entry.CurrentValues["LastUpdatedAt"] = now;
entry.CurrentValues["LastUpdatedBy"] = user;
break;
case EntityState.Added:
entry.CurrentValues["CreatedAt"] = now;
entry.CurrentValues["CreatedBy"] = user;
entry.CurrentValues["LastUpdatedAt"] = now;
entry.CurrentValues["LastUpdatedBy"] = user;
break;
}
}
}
}
}
我认为应是使用的方式,因为这种方式很清晰。
不定义属性
在某些情况下,您可能需要设置列的值而不在模型中定义属性。例如,您可能会公开最后更新的日期,但不会显示谁做了更改。Entity Framework Core 可以通过使用阴影(Shadow )属性来处理这个。阴影属性在OnModelCreating
方法中声明,但在类中不存在。您可以使用ChangeTracker
读取和写入阴影属性的值。
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
}
public class BloggingContext : DbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Declare properties
modelBuilder.Entity<Post>().Property<DateTime>("CreatedAt");
modelBuilder.Entity<Post>().Property<string>("CreatedBy");
modelBuilder.Entity<Post>().Property<DateTime>("LastUpdatedAt");
modelBuilder.Entity<Post>().Property<string>("LastUpdatedBy");
}
private void OnBeforeSaving()
{
var entries = ChangeTracker.Entries();
foreach (var entry in entries)
{
if (entry.Entity is Post post)
{
var now = DateTime.UtcNow;
var user = GetCurrentUser();
switch (entry.State)
{
case EntityState.Modified:
entry.CurrentValues["LastUpdatedAt"] = now;
entry.CurrentValues["LastUpdatedBy"] = user;
break;
case EntityState.Added:
entry.CurrentValues["CreatedAt"] = now;
entry.CurrentValues["CreatedBy"] = user;
entry.CurrentValues["LastUpdatedAt"] = now;
entry.CurrentValues["LastUpdatedBy"] = user;
break;
}
}
}
}
}
来源:https://www.cnblogs.com/tdfblog/p/entity-framework-core-generate-tracking-columns.html


猜你喜欢
- 思考:测试用例执行后,如何生成一个直观漂亮的测试报告呢?分析:1.unittest单元测试框架本身带有一个textTestRunner类,可
- 目录1. 开发之前确定实体类型2. 请求接口时只需要定义自己需要用到的字段3. 使用枚举类型4. DOM元素的类型要正常给5.对象的类型要怎
- 本文实例讲述了Python实现的爬取小说爬虫功能。分享给大家供大家参考,具体如下:想把顶点小说网上的一篇持续更新的小说下下来,就写了一个简单
- 1) 用正式表达式 regexp "[u0391-uFFE5]"2) 用length和char_lengthdrop t
- 大家都知道,在SQL脚本中设置多字段做关键字相对比较简单,例:primary key(id1,id2) ,但用脚本建数据库就比较麻烦了。那么
- 前情提要上文我们分析了挂载组件主要调用了三个函数: createComponentInstance(创建组件实例)、setupCompone
- 在使用ASP来进行后端的数据合法性校验的时候,有些人为满足不同环境下面的数据校验,编写了很多的函数来实现,比如,我们想要校验用户输入的URL
- <% Function XMLEncode(byVal sText) sText = Replace(sText, "&am
- 前言PyTorch是一个开源的深度学习框架,基础教学从开始安装学起,一步一个脚印。提示:以下是本篇文章正文内容,下面案例可供参考一、Pyor
- 本文实例讲述了Python 实现的微信爬虫。分享给大家供大家参考,具体如下:单线程版:import urllib.requestimport
- 前段时间做一个小项目,为了同时存储多条数据,其中有一个功能是解析Excel并把其中的数据存入对应数据库中。花了两天时间,不过一天多是因为用了
- 如果内部修改外部变量需要nonlocal,globaldef f1(): print("in f1..") num=11
- 本文实例讲述了go语言使用pipe读取子进程标准输出的方法。分享给大家供大家参考。具体如下:其核心代码如下:cmd := exec.Comm
- unittest是python的一个单元测试框架关于断言它是用于对一个确定结果和预测结果的一种判断,如果结果正确无任何返回效果,如果结果错误
- python3.7 pip升级 拒绝访问 解决方案pip install --upgrade pip --userps:下面看下python
- 现在大部分网站都使用asp+access构建,这样的话通过下载access数据库简单就可以对网站进行破坏! 而很多的网站都不太重
- 在面向对象的理论中,有两个核心的概念:类和实例。类可以看成是一个模板,实例就是根据这个模板创建出来的对象。但在 Python 里面,类和实例
- 1 文件'''文件存储文件主名.扩展名'''Python中常有的数据文件类型有文本文件、二进
- 今天咱写一个挺实用的工具,就是扫描并获取可用的proxy首先呢,我先百度找了一个网站:http://www.xicidaili.com 作为
- 识别快递单号这次跟老师做项目,这项目大概是流水线上识别快递上的快递单号。首先我尝试了解条形码的基本知识 百度百科:条形码 条形码(barco