如何将parameter passing给DbContext.Database.ExecuteSqlCommand方法?

假设我有一个在Entity Framework中直接执行sql命令的有效需求。 我无法弄清楚如何在我的sql语句中使用参数。 下面的例子(不是我真正的例子)不起作用。

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

ExecuteSqlCommand方法不允许你像ADO.Net那样传入命名参数,这个方法的文档没有提供任何有关如何执行参数化查询的例子。

如何正确指定参数?

原来,这是有效的。

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

尝试这个:

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

你可以:

  1. 传递原始参数并使用{0}语法或
  2. 传递DbParameter子类参数并使用@ParamName语法。

如果使用第一种语法,EF实际上将用DbParamater类包装参数,为它们分配名称,并用生成的参数名称replace{0}。

第一种语法,如果你喜欢,因为你不需要使用工厂或知道什么types的DbParamaters创build(SqlParameter,OracleParamter等)。

试试这个(编辑):

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

以前的想法是错误的。

其他答案在使用Oracle时不起作用。 您需要使用:而不是@

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

Oracle的简化版本。 如果你不想创buildOracleParameter

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

对于asynchronous方法(“ExecuteSqlCommandAsync”),你可以像这样使用它:

 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) }); 
 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; } } 

用法:

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

如果你的下划线数据库数据types是varchar,那么你应该坚持下面的方法。 否则会产生巨大的性能影响。

 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); 

您可以检查Sql分析器来查看差异。