如何将参数传递给DbContext.Database.ExecuteSqlCommand方法?

jes*_*vin 210 entity-framework entity-framework-4.1

让我们假设我有一个在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);
Run Code Online (Sandbox Code Playgroud)

ExecuteSqlCommand方法不允许您传入ADO.Net中的命名参数,并且此方法文档未提供有关如何执行参数化查询的任何示例.

如何正确指定参数?

小智 279

试试这个:

var sql = @"Update [User] SET FirstName = @FirstName WHERE Id = @Id";

ctx.Database.ExecuteSqlCommand(
    sql,
    new SqlParameter("@FirstName", firstname),
    new SqlParameter("@Id", id));
Run Code Online (Sandbox Code Playgroud)

  • @Min,接受的答案不比这个答案容易受到攻击.也许你认为它是使用string.Format - 它不是. (7认同)
  • 这只适用于SQL Server. (5认同)
  • 这确实应该标记为正确的答案,上面的一个容易受到攻击,不是最佳实践。 (2认同)

jes*_*vin 215

事实证明这是有效的.

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

  • @GregB我不认为你在这里是对的.我已经测试过,它不允许我提前终止字符串文字.此外,我查看了源代码,发现它使用DbCommand.CreateParameter将任何原始值包装到参数中.所以没有SQL注入,以及一个很好的简洁方法调用. (93认同)
  • 这将起作用,但是这种机制允许SQL注入,并且还防止数据库在语句再次显示但具有不同值时重用执行计划. (12认同)
  • @JoshGallagher是的,你是对的.我在想一个string.Format场景把它放在一起. (7认同)
  • 它从SQL Server 2008 R2开始不起作用.您将拥有@ p0,@ p2,...,@ pN而不是您传递的参数.请改用`SqlParameter("@ paramName",value)`. (5认同)

小智 67

你可以:

1)传递原始参数并使用{0}语法.例如:

DbContext.Database.SqlQuery("StoredProcedureName {0}", paramName);
Run Code Online (Sandbox Code Playgroud)

2)传递DbParameter子类参数并使用@ParamName语法.

DbContext.Database.SqlQuery("StoredProcedureName @ParamName", 
                                   new SqlParameter("@ParamName", paramValue);
Run Code Online (Sandbox Code Playgroud)

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

第一种语法如果是首选,因为您不需要使用工厂或知道要创建什么类型的DbParamaters(SqlParameter,OracleParamter等).

  • 赞成提及{0}语法与数据库无关."......你[原文如此]不需要使用工厂或知道什么类型的DbParamaters [原文如此]来创造..." (5认同)

Rya*_*n M 19

使用Oracle时,其他答案不起作用.你需要使用:而不是@.

var sql = "Update [User] SET FirstName = :FirstName WHERE Id = :Id";

context.Database.ExecuteSqlCommand(
   sql,
   new OracleParameter(":FirstName", firstName), 
   new OracleParameter(":Id", id));
Run Code Online (Sandbox Code Playgroud)


Lad*_*nka 17

试试这个(编辑):

ctx.Database.ExecuteSqlCommand(sql, new SqlParameter("FirstName", firstName), 
                                    new SqlParameter("Id", id));
Run Code Online (Sandbox Code Playgroud)

以前的想法是错的.

  • DbParameter是抽象的.您必须使用SqlParameter或使用DbFactory来创建DbParameter. (7认同)

Gre*_*Gum 10

对于实体Framework Core 2.0或更高版本,执行此操作的正确方法是:

var firstName = "John";
var id = 12;
ctx.Database.ExecuteSqlCommand($"Update [User] SET FirstName = {firstName} WHERE Id = {id}";
Run Code Online (Sandbox Code Playgroud)

请注意,Entity Framework将为您生成两个参数,因此您可以免受Sql Injection的攻击。

另请注意,它不是:

var firstName = "John";
var id = 12;
var sql = $"Update [User] SET FirstName = {firstName} WHERE Id = {id}";
ctx.Database.ExecuteSqlCommand(sql);
Run Code Online (Sandbox Code Playgroud)

因为这不能保护您免受Sql Injection的影响,并且不生成任何参数。

更多。

  • 我非常喜欢.NET Core 2.0,它让我流下了喜悦的泪水:') (2认同)
  • @GregGum - TIL 关于“FormattableString”。你是对的,这太酷了! (2认同)