实体框架拦截器在插入

时间:2017-02-21 21:00:13

标签: c# entity-framework entity-framework-6

我有一个具有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但是如何修改?

更新 想澄清我知道有更简单的方法可以做到这一点,但这篇文章的目的是使用拦截器,为清楚起见,上面的例子被削减。最终结果将使用属性来标记应受此影响的实体属性。

3 个答案:

答案 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;
    }

}
相关问题