我可以指示EF DbContext使用“真实”参数名称吗?

时间:2014-11-10 23:01:30

标签: c# sql-server entity-framework dbcontext

我使用EF(6,如果重要的话)DbContext子类,并尝试在将实体写入数据库时​​实现拦截器来设置或更新审计数据。

我的拦截器类:

public class EntitySaveInterceptor : BaseDbCommandInterceptor
{
    private const string CreatedAt = "@CreatedAt";
    private const string ModifiedAt = "@ModifiedAt";

    //called for update, but not insert
    public override void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
    {
        var parameters = command.Parameters
            .OfType<DbParameter>()
            .ToDictionary(p => p.ParameterName, p => p);
        if (parameters.ContainsKey(ModifiedAt))
        {
            parameters[ModifiedAt].Value = SystemTime.UtcNow();
        }
    }

    //called for insert
    public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
        var parameters = command.Parameters
            .OfType<DbParameter>()
            .ToDictionary(p => p.ParameterName, p => p);
        if (parameters.ContainsKey(CreatedAt))
        {
            parameters[CreatedAt].Value = SystemTime.UtcNow();
        }
        if (parameters.ContainsKey(ModifiedAt))
        {
            parameters[ModifiedAt].Value = SystemTime.UtcNow();
        }
    }
}

我遇到的问题是这些命令不包含"@CreatedAt""@ModifiedAt"个参数。相反,CreatedAt列的值在名为@3的参数中传递(表示值列表中的零索引位置),以及ModifiedAt列的值(a {当值DateTime?时,{1}}值)在生成的SQL中被硬编码为NULL

我找到了this answer,但对the SqlCommand properties的粗略检查表明null是ODP.Net特定的概念。

很明显,此时我可以检查命令文本,将BindByName语句中的列名与INSERT中的参数名称和NULL匹配子句,并更新VALUES集合以匹配新SQL。但是,如果可能的话,我更喜欢让我的command.Parameters使用与列名称匹配的参数名称。

那么 - 我可以指示我的DbContext或其所依赖的东西在创建DbContext个对象时使用基于属性或列名的参数名吗?

1 个答案:

答案 0 :(得分:2)

另一种方法是覆盖DbContext.SaveChanges并在那里设置属性值。以下是对具有CreatedAt属性的任何添加实体的当前日期/时间的类型不可知(但不一定是最有效)应用的示例:

    public override int SaveChanges()
    {
        foreach( var entry in this.ChangeTracker.Entries() )
        {
            if( entry.State == EntityState.Added && 
                entry.CurrentValues.PropertyNames.Contains( "CreatedAt" ) )
            {
                entry.CurrentValues[ "CreatedAt" ] = DateTime.Now;
            }
        }

        return base.SaveChanges();
    }