我可以指示EF DbContext使用“;真实的“;参数名称

本文关键字:参数 真实 指示 DbContext 使用 我可以 EF | 更新日期: 2023-09-27 18:29:52

我正在使用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"参数。相反,在名为@3的参数中传递CreatedAt列的值(指示值列表中的零索引位置),并且当ModifiedAt列的值为null时,在生成的SQL中将其值(DateTime?值)硬编码为NULL

我找到了这个答案,但粗略检查一下SqlCommand的属性,就会发现BindByName是ODP.Net特定的概念。

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

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

我可以指示EF DbContext使用“;真实的“;参数名称

替代方案是覆盖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();
    }