我有一个具有DateTime
属性LastModified
的实体类,我想使用Entity framework 6.1中的Interceptor功能设置其值
我创建了一个EntityFramework拦截器,用于填充insert命令并正确设置INSERT语句中的值。
我的伪代码看起来像这样
具有生成ID和LastModified
字段
public class Item {
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id{get;set;}
public DateTime LastModified{get;set;}
}
拦截器(使用DbConfiguration添加,此处未涉及)
public class TestInterceptor : IDbCommandTreeInterceptor
{
void IDbCommandTreeInterceptor.TreeCreated(DbCommandTreeInterceptionContext interceptionContext)
{
if (interceptionContext.OriginalResult.DataSpace != DataSpace.SSpace)
return;
var insertCommand = interceptionContext.Result as DbInsertCommandTree;
if (insertCommand != null)
{
//get setClauses of insert command
var setClauses = insertCommand.SetClauses.ToList();
//this index is hardcoded to simplify the example
//that we change the value of one of the setClauses to a custom value.
var clause = setClauses[0];
clause = DbExpressionBuilder.SetClause(clause.Property(),DbExpression.FromDateTime(DateTime.UtcNow));
setClauses[0] = clause;
interceptionContext.Result = DbInsertCommandTree(
insertCommand.MetadataWorkspace,
insertCommand.DataSpace,
insertCommand.Target,
setClauses.AsReadOnly(),
insertCommand.Returning);
}
}
}
创建实例对象的代码
using(var ctx = new MyDbContext()){
var item = new Item();
ctx.Items.Add(item);
ctx.SaveChanges();
}
问题是数据库具有LastModified列的正确值,但item
实例没有。它已正确设置ID。我想我需要修改insertCommand.Returning
但是如何修改?
更新 想澄清我知道有更简单的方法可以做到这一点,但这篇文章的目的是使用拦截器,为清楚起见,上面的例子被削减。最终结果将使用属性来标记应受此影响的实体属性。
答案 0 :(得分:0)
我有一个具有DateTime属性LastModified的实体类,我想使用Entity framework 6.1中的Interceptor功能设置其值
如果要在应用程序的某个位置设置LastModified属性的值,可以在使用ChangeTracker的SaveChanges()之前执行此操作:
var entities = ChangeTracker.Entries().Where(x => x.Entity is Item && (x.State == EntityState.Added || x.State == EntityState.Modified));
foreach (var entity in entities)
{
if (entity.State == EntityState.Added)
{
((BaseEntity)entity.Entity).LastModified = DateTime.UtcNow;
}
}
如果要通过数据库引擎设置LastModified属性的值(使用DEFAULT或TRIGGER),可以使用以下标记属性:
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime? LastUpdated { get; set; }
对于这种场景使用IDbCommandTreeInterceptor看起来像是对我过度工程。
答案 1 :(得分:0)
您可以使用相当不错的库来管理您的拦截器。 EntityHooks
这是您如何轻松实现目标的示例:
public class MyDbContext : DbContext
{
public MyDbContext()
{
this.CreateHook()
.OnSave<Item>()
.Do(i=> i.LastUpdated = DateTime.Now)
}
}
答案 2 :(得分:0)
如此处http://marisks.net/2016/02/27/entity-framework-soft-delete-and-automatic-created-modified-dates/
所述public class LastChangeInterceptor : IDbCommandTreeInterceptor
{
public const string LastChangeColumnName = "LastChange";
public const string LastChangeByColumnName = "LastChangeBy";
public void TreeCreated(DbCommandTreeInterceptionContext interceptionContext)
{
if (interceptionContext.OriginalResult.DataSpace != DataSpace.SSpace)
{
return;
}
var lastChange = DateTime.Now;
var lastChangeBy = HttpContext.Current.User.Identity.Name;
var insertCommand = interceptionContext.Result as DbInsertCommandTree;
var updateCommand = interceptionContext.OriginalResult as DbUpdateCommandTree;
if (insertCommand != null)
{
var setClauses = insertCommand.SetClauses
.Select(clause => clause.UpdateIfMatch(LastChangeColumnName, DbExpression.FromDateTime(lastChange)))
.Select(clause => clause.UpdateIfMatch(LastChangeByColumnName, DbExpression.FromString(lastChangeBy)))
.ToList();
interceptionContext.Result = new DbInsertCommandTree(insertCommand.MetadataWorkspace, insertCommand.DataSpace, insertCommand.Target, setClauses.AsReadOnly(), insertCommand.Returning);
}
else if (updateCommand != null)
{
var setClauses = updateCommand.SetClauses
.Select(clause => clause.UpdateIfMatch(LastChangeColumnName, DbExpression.FromDateTime(lastChange)))
.Select(clause => clause.UpdateIfMatch(LastChangeByColumnName, DbExpression.FromString(lastChangeBy)))
.ToList();
interceptionContext.Result = new DbUpdateCommandTree(updateCommand.MetadataWorkspace, updateCommand.DataSpace, updateCommand.Target, updateCommand.Predicate, setClauses.AsReadOnly(), null);
}
}
}
public static class Extensions
{
public static DbModificationClause UpdateIfMatch(this DbModificationClause clause, string property, DbExpression value)
{
var propertyExpression = (DbPropertyExpression)((DbSetClause)clause).Property;
if (propertyExpression.Property.Name == property)
{
return DbExpressionBuilder.SetClause(propertyExpression, value);
}
return clause;
}
}