使用Entity Framework 6属性,存储行创建日期和上次更新日期

时间:2015-03-26 12:15:03

标签: c# entity-framework

我正在使用Entity Framework 6.1.3创建模型,我想存储创建行的时间和上次更新时的UTC日期和时间。

我有以下模型(简化):

namespace Sapphire.Cms.Models {
    using System;
    using System.ComponentModel.DataAnnotations;

    public class SiteTree {
        [Required]
        [DataType(DataType.DateTime)]
        [Display(Name = "Created")]
        public DateTime Created { get; set; }

        [Required]
        [DataType(DataType.DateTime)]
        [Display(Name = "Last Updated")]
        public DateTime LastUpdated { get; set; }
    }
}

对于Created字段,我想在名为Created in MSSQL的日期时间字段中存储创建行的UTC日期和时间。

对于LastUpdated字段,我想在每次更新行时,在MSSQL中名为LastUpdated的日期时间字段中存储上次更新行的UTC日期和时间。

我希望能够使用属性,以便我可以指示何时应自动填充此数据。

例如,对于LastUpdated属性:

    [Required]
    [DataType(DataType.DateTime)]
    [Display(Name = "Last Updated")]
    [TrackLastUpdated]
    public DateTime LastUpdated { get; set; }

我希望能够将这些属性用于其他模型。

服务器上的时区从GMT变为BST并返回,因此将此值存储在UTC中并以UTC格式输出值非常重要。

在SO上有类似的问题,但没有一个使用我能看到的属性:

我希望EF已经有了一些属性来做到这一点,但我似乎无法找到它们。如果不是,有人可以解释我如何实现这一目标吗?

1 个答案:

答案 0 :(得分:4)

好的,看看这个。这就是我在这里使用的。首先,创建此接口并使用您要审核的类来装饰您的类。

public interface IAuditableEntity
{
    DateTime CreatedDateUtc { get; set; }
    DateTime ModifiedDateUtc { get; set; }

    string CreatedBy { get; set; }
    string ModifiedBy { get; set; }
}

您的数据上下文构造函数需要连接ObjectContext的保存事件。请忽略时钟位,没有必要。

public MyContext()
    : this(null, "Name=MyContext")
{
}

public MyContext(IClock clock, string connectionString)
    : base(connectionString)
{
    _clock = clock;

    var objCtx = ((IObjectContextAdapter) this).ObjectContext;
    objCtx.ObjectMaterialized += ObjectMaterialized;
    objCtx.SavingChanges += ObjectContext_SavingChanges;
}

这是处理程序,以及神奇发生的地方。它会获取所有新的和修改过的实体,并在保存之前根据需要设置字段:

private static void ObjectContext_SavingChanges(object sender, EventArgs e)
{
    var objCtx = sender as ObjectContext;
    if (objCtx == null)
        return;

    var username = Thread.CurrentPrincipal != null ? Thread.CurrentPrincipal.Identity.Name : String.Empty;
    var auditableEntries =
        (from entry in objCtx.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified)
            where !entry.IsRelationship
            let entity = entry.Entity as IAuditableEntity
            where entity != null
            select new
            {
                entity,
                entry.State
            }).ToList();

    foreach (var entry in auditableEntries.Where(x => x.State == EntityState.Added))
    {
        entry.entity.CreatedDateUtc = DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Utc);
        entry.entity.CreatedBy = username;
    }

    foreach (var entry in auditableEntries.Where(x => x.State == EntityState.Modified))
    {
        entry.entity.ModifiedDateUtc = DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Utc);
        entry.entity.ModifiedBy = username;
    }
}

请注意,我尚未完全测试此代码。它可能有一个错误。您可以使用Convention和自定义属性执行此操作,但我不太确定。