I'm using an EF (6, if it matters) DbContext subclass, and trying to implement an interceptor to set or update auditing data when an entity is written to the database.
My interceptor class:
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();
}
}
}
The problem I'm encountering is that these commands don't contain "@CreatedAt" or "@ModifiedAt" parameters. Instead, the value for the CreatedAt column is passed in a parameter named @3 (indicating the zero-indexed position in the values list), and the value for the ModifiedAt column (a DateTime? value) is hard-coded as NULL in the generated SQL when its value is null.
I found this answer, but a cursory examination of the SqlCommand properties reveals that BindByName is an ODP.Net specific concept.
It's obvious that I can inspect the command text at this point, match the column names in the INSERT statement with the parameter names and NULLs in the VALUES clause, and update the command.Parameters collection to match the new SQL. But, if possible, I'd prefer to have my DbContext use parameter names that match up with the column names.
So - can I instruct my DbContext, or something upon which it relies, to use parameter names based on property or column names when it is creating DbCommand objects?