Can I instruct EF DbContext to use "real" parameter names?
I am using an EF (6 if it matters) subclass DbContext
and trying to implement an interceptor to set or update audit data when an object 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 am having is that these commands do not contain parameters "@CreatedAt"
or "@ModifiedAt"
. Instead, the value for the column CreatedAt
is passed by a parameter named @3
(indicating zero indexing in the list of values), and the value for column ModifiedAt
(a DateTime?
) is complex - encoded as NULL
in the generated SQL when its value is NULL
.
I found this answer , but a cursory analysis of the propertySqlCommand
reveals what BindByName
a specific ODP.Net concept is.
Obviously I can check the command text at this point, match the column names in the statement INSERT
with the parameter names and NULL
in the clause, VALUES
and update the collection command.Parameters
to match the new SQL. But, if possible, I would prefer to use parameter names DbContext
that match the column names.
So - can I instruct my, DbContext
or whatever it relies on, to use parameter names based on property or column names when it creates objects DbCommand
?
source to share
An alternative would be to override DbContext.SaveChanges
and set property values there. Below is an example of type agnostic (although not necessarily the most efficient) current date / time for any added object with a property 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();
}
source to share