web-dev-qa-db-fra.com

Comment passer des paramètres à la méthode DbContext.Database.ExecuteSqlCommand?

Supposons simplement que j'ai un besoin valide d'exécuter directement une commande SQL dans Entity Framework. Je ne parviens pas à comprendre comment utiliser les paramètres dans mon instruction SQL. L'exemple suivant (pas mon exemple réel) ne fonctionne pas.

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

La méthode ExecuteSqlCommand ne vous permet pas de passer des paramètres nommés comme dans ADO.Net et la documentation de cette méthode ne donne aucun exemple sur la façon d'exécuter une requête paramétrée.

Comment spécifier les paramètres correctement?

191
jessegavin

Il s'avère que cela fonctionne.

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

Essaye ça:

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

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

Tu peux soit:

1) Passez des arguments bruts et utilisez la syntaxe {0}. Par exemple:

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

2) Passez les arguments de la sous-classe DbParameter et utilisez la syntaxe @ParamName. 

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

Si vous utilisez la première syntaxe, EF encapsulera vos arguments avec les classes DbParamater, leur attribuera des noms et remplacera {0} par le nom de paramètre généré.

La première syntaxe est préférable si vous n'avez pas besoin d'utiliser une fabrique ni de savoir quel type de DbParamaters créer (SqlParameter, OracleParamter, etc.).

63
Will Brown

Les autres réponses ne fonctionnent pas avec Oracle. Vous devez utiliser : au lieu de @.

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

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

Essayez ceci (édité):

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

L'idée précédente était fausse. 

16
Ladislav Mrnka

Pour l'entité Framework Core 2.0 ou une version ultérieure, procédez comme suit:

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

Notez qu'Entity Framework produira les deux paramètres pour vous, de sorte que vous êtes protégé de Sql Injection.

Notez également que ce n'est pas:

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

car cela ne vous protège PAS de Sql Injection et aucun paramètre n’est produit.

Voir ceci pour plus.

4
Greg Gum

Version simplifiée pour Oracle. Si vous ne voulez pas créer 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 });

C'est si simple !!!

Image pour connaître la référence du paramètre

 enter image description here

2
Zaw

Pour la méthode async ("ExecuteSqlCommandAsync"), vous pouvez l'utiliser comme ceci:

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

Si vos types de données de base de données sous-jacents sont varchar, vous devez vous en tenir à l’approche ci-dessous. Sinon, la requête aurait un impact énorme sur les performances.

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

Vous pouvez vérifier le profileur SQL pour voir la différence.

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

Usage:

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

Les procédures stockées peuvent être exécutées comme ci-dessous

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

Plusieurs paramètres dans une procédure stockée comportant plusieurs paramètres dans vb:

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

Pour .NET Core 2.2, vous pouvez utiliser FormattableString pour le SQL dynamique.

//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