entity-framework entity-framework-4.1

entity framework - ¿Cómo pasar parámetros al método DbContext.Database.ExecuteSqlCommand?



entity-framework entity-framework-4.1 (10)

Las otras respuestas no funcionan cuando se usa Oracle. Debe usar : lugar de @ .

var sql = "Update [User] SET FirstName = :FirstName WHERE Id = :Id"; context.Database.ExecuteSqlCommand( sql, new OracleParameter(":FirstName", firstName), new OracleParameter(":Id", id));

Supongamos que tengo una necesidad válida para ejecutar directamente un comando sql en Entity Framework. Tengo problemas para descubrir cómo usar parámetros en mi declaración sql. El siguiente ejemplo (no es mi ejemplo real) no funciona.

var firstName = "John"; var id = 12; var sql = @"Update [User] SET FirstName = @FirstName WHERE Id = @Id"; ctx.Database.ExecuteSqlCommand(sql, firstName, id);

El método ExecuteSqlCommand no le permite pasar parámetros nombrados como en ADO.Net y la documentación de este método no proporciona ningún ejemplo sobre cómo ejecutar una consulta parametrizada.

¿Cómo especifico los parámetros correctamente?


Para el método async ("ExecuteSqlCommandAsync") puede usarlo así:

var sql = @"Update [User] SET FirstName = @FirstName WHERE Id = @Id"; await ctx.Database.ExecuteSqlCommandAsync( sql, parameters: new[]{ new SqlParameter("@FirstName", firstname), new SqlParameter("@Id", id) });


Prueba esto (editado):

ctx.Database.ExecuteSqlCommand(sql, new SqlParameter("FirstName", firstName), new SqlParameter("Id", id));

La idea anterior estaba mal.


Prueba esto:

var sql = @"Update [User] SET FirstName = @FirstName WHERE Id = @Id"; ctx.Database.ExecuteSqlCommand( sql, new SqlParameter("@FirstName", firstname), new SqlParameter("@Id", id));


Resulta que esto funciona.

var firstName = "John"; var id = 12; var sql = "Update [User] SET FirstName = {0} WHERE Id = {1}"; ctx.Database.ExecuteSqlCommand(sql, firstName, id);


Si los tipos de datos subyacentes de su base de datos son varchar, debe seguir el siguiente enfoque. De lo contrario, la consulta tendría un gran impacto en el rendimiento.

var firstName = new SqlParameter("@firstName", System.Data.SqlDbType.VarChar, 20) { Value = "whatever" }; var id = new SqlParameter("@id", System.Data.SqlDbType.Int) { Value = 1 }; ctx.Database.ExecuteSqlCommand(@"Update [User] SET FirstName = @firstName WHERE Id = @id" , firstName, id);

Puede verificar Sql profiler para ver la diferencia.


Tu también puedes:

1) Pase argumentos sin formato y use la sintaxis {0}. P.ej:

DbContext.Database.SqlQuery("StoredProcedureName {0}", paramName);

2) Pase los argumentos de la subclase DbParameter y use la sintaxis @ParamName.

DbContext.Database.SqlQuery("StoredProcedureName @ParamName", new SqlParameter("@ParamName", paramValue);

Si usa la primera sintaxis, EF en realidad envolverá sus argumentos con las clases DbParamater, les asignará nombres y reemplazará {0} con el nombre del parámetro generado.

La primera sintaxis, si se prefiere, porque no necesita usar una fábrica o saber qué tipo de DbParamaters crear (SqlParameter, OracleParamter, etc.).


Versión simplificada para Oracle. Si no quieres crear OracleParameter

var sql = "Update [User] SET FirstName = :p0 WHERE Id = :p1"; context.Database.ExecuteSqlCommand(sql, firstName, id);


podrías hacer esto

int id = 1; string firstname = "John", sql = $"Update [User] SET FirstName = ''{firstname}'' WHERE Id = {id}"; context.Database.ExecuteSqlCommand(sql);

Algunos pueden pensar que no es una buena práctica, así que aquí hay otra

object[] params = new object[]{"John", 1}; string sql = "UPDATE [User] SET FirstName = {0} WHERE Id = {1}"; context.Database.ExecuteSqlCommand(sql, params);

Personalmente creo que el primero es más limpio y mucho más fácil de leer y depurar. Y funciona así que no hay razón para rechazarlo. He tenido los mismos problemas exactos con ambas declaraciones. Y la inyección SQL está más en el usuario para controlar que confiar en el sistema.

Gracias por el voto negativo a una solución viable.


public static class DbEx { public static IEnumerable<T> SqlQueryPrm<T>(this System.Data.Entity.Database database, string sql, object parameters) { using (var tmp_cmd = database.Connection.CreateCommand()) { var dict = ToDictionary(parameters); int i = 0; var arr = new object[dict.Count]; foreach (var one_kvp in dict) { var param = tmp_cmd.CreateParameter(); param.ParameterName = one_kvp.Key; if (one_kvp.Value == null) { param.Value = DBNull.Value; } else { param.Value = one_kvp.Value; } arr[i] = param; i++; } return database.SqlQuery<T>(sql, arr); } } private static IDictionary<string, object> ToDictionary(object data) { var attr = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance; var dict = new Dictionary<string, object>(); foreach (var property in data.GetType().GetProperties(attr)) { if (property.CanRead) { dict.Add(property.Name, property.GetValue(data, null)); } } return dict; } }

Uso:

var names = db.Database.SqlQueryPrm<string>("select name from position_category where id_key=@id_key", new { id_key = "mgr" }).ToList();