web-dev-qa-db-ja.com

パラメーターを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のように名前付きパラメーターを渡すことはできません。また、 このメソッドのドキュメント は、パラメーター化されたクエリの実行方法の例を示していません。

パラメータを正しく指定するにはどうすればよいですか?

197
jessegavin

これが機能することがわかりました。

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

これを試して:

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

ctx.Database.ExecuteSqlCommand(
    sql,
    new SqlParameter("@FirstName", firstname),
    new SqlParameter("@Id", id));
265
Robert te Kaat

次のいずれかが可能です。

1)生の引数を渡し、{0}構文を使用します。例えば:

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

2)DbParameterサブクラスの引数を渡し、@ ParamName構文を使用します。

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

最初の構文を使用する場合、EFは実際に引数をDbParamaterクラスでラップし、それらに名前を割り当て、{0}を生成されたパラメーター名に置き換えます。

ファクトリを使用する必要がないため、または作成するDbParamaterの種類(SqlParameter、OracleParamterなど)を知る必要がないため、最初の構文が推奨されます。

64
Will Brown

Oracleを使用する場合、他の回答は機能しません。 :の代わりに@を使用する必要があります。

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

context.Database.ExecuteSqlCommand(
   sql,
   new OracleParameter(":FirstName", firstName), 
   new OracleParameter(":Id", id));
18
Ryan M

これを試してください(編集済み):

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

前のアイデアは間違っていました。

16
Ladislav Mrnka

エンティティFramework Core 2.0以上の場合、これを行う正しい方法は次のとおりです。

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

Entity Frameworkが2つのパラメーターを生成するため、SQLインジェクションから保護されることに注意してください。

また、以下ではないことに注意してください。

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

これは、SQLインジェクションからユーザーを保護しないため、パラメーターが生成されないためです。

詳しくは this をご覧ください。

6
Greg Gum

Oracleの簡易バージョン。 OracleParameterを作成したくない場合

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

ctx.Database.ExecuteSqlCommand(@"Update [User] SET FirstName = {0} WHERE Id = {1}"
, new object[]{ firstName, id });

これはとても簡単です!!!

パラメータ参照を知るための画像

enter image description here

2
Zaw

Asyncメソッド( "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)
    });
2
Magu

基礎となるデータベースのデータ型が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プロファイラーをチェックして、違いを確認できます。

1
akd
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();
1
Neco

ストアドプロシージャは次のように実行できます。

 string cmd = Constants.StoredProcs.usp_AddRoles.ToString() + " @userId, @roleIdList";
                        int result = db.Database
                                       .ExecuteSqlCommand
                                       (
                                          cmd,
                                           new SqlParameter("@userId", userId),
                                           new SqlParameter("@roleIdList", roleId)
                                       );
0

Vbに複数のパラメーターを持つストアドプロシージャの複数のパラメーター:

Dim result= db.Database.ExecuteSqlCommand("StoredProcedureName @a,@b,@c,@d,@e", a, b, c, d, e)
0
Dani

.NET Core 2.2では、動的SQLにFormattableStringを使用できます。

//Assuming this is your dynamic value and this not coming from user input
var tableName = "LogTable"; 
// let's say target date is coming from user input
var targetDate = DateTime.Now.Date.AddDays(-30);
var param = new SqlParameter("@targetDate", targetDate);  
var sql = string.Format("Delete From {0} Where CreatedDate < @targetDate", tableName);
var froamttedSql = FormattableStringFactory.Create(sql, param);
_db.Database.ExecuteSqlCommand(froamttedSql);
0
Circuit Breaker