修改后实体框架代码第一个日期时间字段更新
本文关键字:日期 时间 字段 更新 第一个 代码 实体 框架 修改 | 更新日期: 2023-09-27 18:11:30
我有以下实体:
public class User
{
public int UserId { get; set; }
public string UserName { get; set; }
public string UserAddress { get; set; }
public DateTime CreateDate { get; set; }
public DateTime? UpdateDate { get; set; }
}
如何使User
实体的UpdateDate
字段在更新时变为服务器DateTime
?也就是说,每当数据库中的实体被修改时,UpdateDate
字段就会更改为该确切的日期和时间,就像说UpdateDate = new DateTime(Datetime.Now.Ticks)
首先,考虑到如果要存储本地时间,DateTimeOffset
是更好的选择。或者,您可以使用基于utc的DateTime
,但我将在本例中展示DateTimeOffset
。不要为此目的存储基于本地的DateTime
,因为您将遇到时区和夏令时的问题。参见:反对DateTime.Now的案例
接下来,考虑一个公共接口,您可以将其用于希望跟踪创建/更新值的实体。
public interface IDatedEntity
{
DateTimeOffset Created { get; set; }
DateTimeOffset Updated { get; set; }
}
将该接口及其属性应用于您正在使用的实体。
public class User : IDatedEntity
{
// ...
public DateTimeOffset Created { get; set; }
public DateTimeOffset Updated { get; set; }
}
现在,在您的数据库上下文中,您可以附加到SavingChanges
事件并应用所需的行为:
public class MyContext : DbContext
{
public DbSet<User> Users { get; set; }
public MyContext()
{
var objectContext = ((IObjectContextAdapter)this).ObjectContext;
objectContext.SavingChanges += (sender, args) =>
{
var now = DateTimeOffset.Now;
foreach (var entry in this.ChangeTracker.Entries<IDatedEntity>())
{
var entity = entry.Entity;
switch (entry.State)
{
case EntityState.Added:
entity.Created = now;
entity.Updated = now;
break;
case EntityState.Modified:
entity.Updated = now;
break;
}
}
this.ChangeTracker.DetectChanges();
};
}
}
注意最后对DetectChanges
的调用,这将确保新更新的日期值应用于所有修改的实体。
如果你正在使用。net Core和实体框架Core,我发现最简单的方法是在数据库上下文上使用内置的ChangeTracker
,并订阅它的事件ChangeTracker_StateChanged
,这将在实体改变状态时触发。我是这样实现的:
public abstract class BaseDbContext<T> : DbContext where T : DbContext
{
public BaseDbContext(DbContextOptions<T> options) : base(options)
{
this.ChangeTracker.StateChanged += ChangeTracker_StateChanged;
}
private void ChangeTracker_StateChanged(object sender, EntityStateChangedEventArgs e)
{
if (e.NewState == EntityState.Added || e.NewState == EntityState.Modified)
{
var entity = (BaseEntity)e.Entry.Entity;
entity.UpdatedDate = DateTime.UtcNow;
}
}
}
然后我在几个项目中使用这个BaseDbContext,所有这些项目的实体都用UpdatedDate
字段扩展BaseEntity
。
您只能在迁移时这样做。将UpdateDate属性的defaultSqlValue参数设置为"GETDATE()"或"GETUTCDATE()",当您修改或添加新实体时,您需要将其值设置为null。
2022年,我们可以使用注释来设置计算列和标识列:
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public DateTime created { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime updated { get; set; }
https://learn.microsoft.com/en-us/ef/core/modeling/generated-properties?tabs=data-annotations默认值
设置默认值:
// Generate default value for created and updated column types, if they exist
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
modelBuilder.Entity(entityType.Name, x =>
{
if (entityType.FindProperty("created") != null)
x.Property("created").HasDefaultValueSql("getdate()");
if (entityType.FindProperty("updated") != null)
x.Property("updated").HasDefaultValueSql("getdate()");
});
}