修改后实体框架代码第一个日期时间字段更新

本文关键字:日期 时间 字段 更新 第一个 代码 实体 框架 修改 | 更新日期: 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()");
    });
}