如何设置创建日期和修改日期以在DB第一种方法中进行设置

时间:2016-05-17 20:45:52

标签: entity-framework ef-database-first

在我们的应用程序的每个SQL表中,我们都有“CreatedDate”和“ModifiedDate”列。我们正在使用DB第一种方法。当我保存数据时,我希望自动填充这两列。一种方法是在SQL表列本身上将默认值设置为getdate()。所以这将部分地解决问题。这意味着它将设置CreatedDate&当实体是新的时,ModifiedDate。 但是,当我编辑/更新实体时,我只想更新ModifiedDate 使用Code第一种方法有很多文章在做这件事。但我们正在使用DB第一种方法 我有什么选择?

6 个答案:

答案 0 :(得分:8)

您可以在DbContext中覆盖SaveChanges方法并获取已添加和修改实体的列表,如果添加了Set CreatedDate,则修改后设置为ModifiedDate。

public override int SaveChanges()
{
    var AddedEntities = ChangeTracker.Entries<Entity>().Where(E => E.State == EntityState.Added).ToList();

    AddedEntities.ForEach(E => 
    {
        E.CreatedDate = DateTime.Now;
    });

    var ModifiedEntities = ChangeTracker.Entries<Entity>().Where(E => E.State == EntityState.Modified).ToList();

    ModifiedEntities.ForEach(E => 
    {
        E.ModifiedDate = DateTime.Now;
    });

    return base.SaveChanges();
}

您还可以编写一个具有两个DateTime属性的接口,并使您的实体继承它们。

interface IEntityDate
{
    DateTime AddedDate { set; get;}
    DateTime ModifiedDate { set; get;}
}

class Entity : IEntityDate
{
    public DateTime AddedDate { set; get;}
    public DateTime ModifiedDate { set; get;}
}

答案 1 :(得分:7)

对于那些使用异步系统(SaveChangesAsync)和.net核心的人来说,最好将下面的代码添加到DbContext类。

    public override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default(CancellationToken))
    {
        var AddedEntities = ChangeTracker.Entries().Where(E => E.State == EntityState.Added).ToList();

        AddedEntities.ForEach(E =>
        {
            E.Property("CreationTime").CurrentValue = DateTime.Now;
        });

        var EditedEntities = ChangeTracker.Entries().Where(E => E.State == EntityState.Modified).ToList();

        EditedEntities.ForEach(E =>
        {
            E.Property("ModifiedDate").CurrentValue = DateTime.Now;
        });

        return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
    }

您也可以定义类或接口,如下所示。

public class SaveConfig
{
    public DateTime CreationTime { get; set; }
    public DateTime? ModifiedDate { get; set; }
}

只从SaveConfig实体继承实体。

答案 2 :(得分:7)

如果要覆盖OnSave,则必须覆盖所有保存方法。在EF core 2.1中,可以对ChangeTracked和events使用更好的解决方案。例如:

您可以创建接口或基类,如下例所示:

public interface IUpdateable 
{ 
    DateTime ModificationDate{ get; set; }

}

public class SampleEntry : IUpdateable
{
    public int Id { get; set; }
    DateTime ModificationDate{ get; set; }

} 

然后在上下文创建中将事件添加到更改跟踪器:

context.ChangeTracker.StateChanged += context.ChangeTracker_StateChanged;

和方法:

private void ChangeTracker_StateChanged(object sender, Microsoft.EntityFrameworkCore.ChangeTracking.EntityStateChangedEventArgs e)
    {
        if(e.Entry.Entity is IUpdateable && e.Entry.State == EntityState.Modified)
        {
            var entry = ((IUpdateable)e.Entry.Entity);
            entry.ModyficationDate = DateTime.Now;

        }
    }

这更容易,您不必重写所有方法;

答案 3 :(得分:2)

我喜欢这样更通用的方法:

interface IEntityDate
{
    DateTime CreatedDate { get; set; }

    DateTime UpdatedDate { get; set; }
}

public abstract class EntityBase<T1>: IEntityDate
{
    public T1 Id { get; set; }

    public virtual DateTime CreatedDate { get; set; }
    public virtual string CreatedBy { get; set; }
    public virtual DateTime UpdatedDate { get; set; }
    public virtual string UpdatedBy { get; set; }
}

public override int SaveChanges()
{
    var now = DateTime.Now;

    foreach (var changedEntity in ChangeTracker.Entries())
    {
        if (changedEntity.Entity is IEntityDate entity)
        {
            switch (changedEntity.State)
            {
                case EntityState.Added:
                    entity.CreatedDate = now;
                    entity.UpdatedDate = now;
                    break;

                case EntityState.Modified:
                    Entry(entity).Property(x => x.CreatedDate).IsModified = false;
                    entity.UpdatedDate = now;
                    break;
            }
        }
    }

    return base.SaveChanges();
}

答案 4 :(得分:1)

这是我在EF Core 2.1中解决的方法:

我有一个基本模型,该模型继承了类似于以下内容的接口:

public interface IAuditableModel
{
    DateTime Created { get; }
    DateTime? Updated { get; set; }
}

public class BaseModel : IAuditableModel
{
    public BaseModel()
    {
    }

    public int Id { get; set; }

    public DateTime Created { get; private set; }

    public DateTime? Updated { get; set; }
}

然后,在我的DbContext中:

public override int SaveChanges()
    {
        var added = ChangeTracker.Entries<IAuditableModel>().Where(E => E.State == EntityState.Added).ToList();

        added.ForEach(E =>
        {
            E.Property(x => x.Created).CurrentValue = DateTime.UtcNow;
            E.Property(x => x.Created).IsModified = true;
        });

        var modified = ChangeTracker.Entries<IAuditableModel>().Where(E => E.State == EntityState.Modified).ToList();

        modified.ForEach(E =>
        {
            E.Property(x => x.Updated).CurrentValue = DateTime.UtcNow;
            E.Property(x => x.Updated).IsModified = true;

            E.Property(x => x.Created).CurrentValue = E.Property(x => x.Created).OriginalValue;
            E.Property(x => x.Created).IsModified = false;
        });

        return base.SaveChanges();
    }

这可以避免对任何属性名称进行硬编码,并可以将特定接口灵活地应用于所选模型。就我而言,我希望在大多数模型上都能做到这一点,因此我将其应用于所有其他模型都继承自的BaseModel。

我也在编辑这些模型的视图上发现,由于我没有将创建的时间戳加载到页面上,因此创建的时间戳被清除了。结果,当模型绑定回发时,该属性被删除,将我创建的时间戳有效地设置为0。

答案 5 :(得分:0)

我做了类似的事情@Arash提出的公共覆盖“任务SaveChangesAsync”,区别在于我的设置我只想更新实际具有CreatedDate / ModifiedDate属性的实体,这就是我提出的用。与@Arash非常相似,但也许它可以帮助某人。 添加了几个常量EntityCreatedPropertyName和EntityModifiedPropertyName来定义属性的名称,这样我就不必为那些使用它们的人使用重复的字符串。

    public override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default(CancellationToken))
    {
        #region Automatically set "CreatedDate" property on an a new entity
        var AddedEntities = ChangeTracker.Entries().Where(E => E.State == EntityState.Added).ToList();

        AddedEntities.ForEach(E =>
        {
            var prop = E.Metadata.FindProperty(EntityCreatedPropertyName);
            if (prop != null)
            {
                E.Property(EntityCreatedPropertyName).CurrentValue = DateTime.Now;
            }
        });
        #endregion

        #region Automatically set "ModifiedDate" property on an a new entity
        var EditedEntities = ChangeTracker.Entries().Where(E => E.State == EntityState.Modified).ToList();

        EditedEntities.ForEach(E =>
        {
            var prop = E.Metadata.FindProperty(EntityModifiedPropertyName);
            if (prop != null)
            {
                E.Property(EntityModifiedPropertyName).CurrentValue = DateTime.Now;
            }
        });
        #endregion

        return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
    }