我可以指示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
子句中的参数名和NULL
s相匹配,并更新command.Parameters
集合以匹配新的SQL。但是,如果可能的话,我更希望DbContext
使用与列名匹配的参数名。
那么,在创建DbCommand
对象时,我可以指示我的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();
}