ef6 中的自动 CreatedAt 和 UpdatedAt 字段 OnModelCreating()
Posted
技术标签:
【中文标题】ef6 中的自动 CreatedAt 和 UpdatedAt 字段 OnModelCreating()【英文标题】:Automatic CreatedAt and UpdatedAt fields OnModelCreating() in ef6 【发布时间】:2018-01-07 20:12:55 【问题描述】:我的User
模型中有CreatedAt
和UpdatedAt
列。
User.cs
public string Name get; set;
public DateTime? CreatedAt get; set;
public DateTime? UpdatedAt get; set;
要求
当我们SaveChanges()
用户记录时,CreatedAt
和UpdatedAt
应该自动保存例如:DateTime.UtcNow
当我更新User
记录时,只有UpdatedAt
列应该更新为当前日期时间。
对于所有其他型号,这应该会自动发生,可能是OnModelCreating()
中的某些配置。
我希望这种行为能够从数据库和其他地方找到latest
记录。
我正在使用code first
迁移方法
我正在使用 mysql 服务器,MySql.Data
,MySql.Data.Entity.EF6
。
更新
我添加了BaseEntity.cs
模型
public abstract class BaseEntity
public DateTime CreatedAt get; set;
public DateTime UpdatedAt get; set;
从 BaseEntity 继承用户
public class User : BaseEntity
public int Id get; set;
public int FullName get; set;
并更新了迁移以包括 defaultValueSql()
AddColumn("dbo.Users", "CreatedAt", c => c.DateTime(nullable: false, precision: 0, defaultValueSql: "NOW()"));
AddColumn("dbo.Users", "UpdatedAt", c => c.DateTime(nullable: false, precision: 0, defaultValueSql: "NOW()"));"
现在,需要一种方法来修复每次更新中的 UpdatedAt
列。
【问题讨论】:
先用数据库,再用sql实现? 不,我先使用代码。我找到了AddColumn("dbo.Users", "CreatedAt", c => c.DateTime(nullable: false, precision: 0, defaultValueSql: "UTC_TIMESTAMP()"));
但update-migration
给出了语法错误。
但在 mysql 查询中运行 select UTC_TIMESTAMP();
会给出当前日期时间戳
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UTC_TIMESTAMP()' at line 1
【参考方案1】:
终于找到了解决我的问题的方法。因为我们可以将数据库从MySql
更改为postgresql
或Ms Sql server
,所以使用sql 查询添加默认值似乎不是正确的解决方案。
这是我的解决方法。
添加Base
型号
public abstract class BaseEntity
public DateTime? CreatedAt get; set;
public DateTime? UpdatedAt get; set;
从这个基础模型继承你的所有模型,在我的例子中是User
public class User : BaseEntity
public int Id get; set;
public int FullName get; set;
如果您使用代码优先方法,请不要忘记生成迁移。迁移应该足够简单:
例子:
AddColumn("dbo.Users", "CreatedAt", c => c.DateTime(precision: 0));
AddColumn("dbo.Users", "UpdatedAt", c => c.DateTime(precision: 0));
最后一步是在您的上下文中覆盖 SaveChanges()
和 SaveChangesAsync()
:
public class MyDbContext : DbContext
public DbSet<User> Users get; set;
public override int SaveChanges()
AddTimestamps();
return base.SaveChanges();
public override async Task<int> SaveChangesAsync()
AddTimestamps();
return await base.SaveChangesAsync();
private void AddTimestamps()
var entities = ChangeTracker.Entries()
.Where(x => x.Entity is BaseEntity && (x.State == EntityState.Added || x.State == EntityState.Modified));
foreach (var entity in entities)
var now = DateTime.UtcNow; // current datetime
if (entity.State == EntityState.Added)
((BaseEntity)entity.Entity).CreatedAt = now;
((BaseEntity)entity.Entity).UpdatedAt = now;
【讨论】:
请注意,对于那些使用 EF Core 的人,这不起作用。实体还不能从抽象基类继承字段。 MS 将此称为 Table-Per-Concrete-Type,但尚不支持。功能发布目标是 EF 5.0,目前处于预览阶段,希望很快。这将使许多领域模型更加清晰。 docs.microsoft.com/en-us/ef/core/modeling/inheritance【参考方案2】:您可以像这样定义自己的interface
:
public interface ITiming
DateTime CreatedAt get; set;
DateTime UpdatedAt get; set;
现在让你想要的每个模型都实现这个接口。
并像这样给自己写一个ExtionsionMethod
:
public static SaveChangesTimed(this YourDbContext _context, ITiming timed)
timed.CreatedAt = DateTime.Now;
timed.UpdatedAt = Datetime.Now;
_context.SaveChanges();
【讨论】:
谢谢 Yggraz,但我有一个问题:看起来它会更新CreatedAt
和 UpdatedAt
每次 SaveChanges()
被击中,但我想第一次更新 CreatedAt
从那时起它不应该改变,只有UpdatedAt
应该从下一次改变。如果我误解了,请纠正我。
是的,如果你想要这个,那么你必须自动实现 CreatedAt
link 并使用仅用于 UpdatedAt 的扩展【参考方案3】:
我看到@przbadu 的帖子,我有点困难。 我正在使用 dotnet core 2.2,我需要将 SaveChangeAsync 方法更改为:
public override int SaveChanges()
AddTimestamps();
return base.SaveChanges();
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
AddTimestamps();
return base.SaveChangesAsync();
private void AddTimestamps()
var entities = ChangeTracker.Entries()
.Where(x => x.Entity is BaseEntity && (x.State == EntityState.Added || x.State == EntityState.Modified));
foreach (var entity in entities)
var now = DateTime.UtcNow; // current datetime
if (entity.State == EntityState.Added)
((BaseEntity)entity.Entity).CreatedAt = now;
((BaseEntity)entity.Entity).UpdatedAt = now;
【讨论】:
以上是关于ef6 中的自动 CreatedAt 和 UpdatedAt 字段 OnModelCreating()的主要内容,如果未能解决你的问题,请参考以下文章
如何在 aws AppSync 中按 createdAt 和 updatedAt 排序和过滤?
防止在对象集包含时覆盖 Cloud Function 中的 createdAt 和 updatedAt