我正在使用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已经有了一些属性来做到这一点,但我似乎无法找到它们。如果不是,有人可以解释我如何实现这一目标吗?
答案 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
和自定义属性执行此操作,但我不太确定。