242 votes

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

Supposons que j'aie un besoin valide d'exécuter directement une commande sql dans Entity Framework. J'ai du mal à comprendre comment utiliser les paramètres dans mon instruction sql. L'exemple suivant (qui n'est 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 permet pas de passer des paramètres nommés, comme c'est le cas dans ADO.Net et dans le système de gestion des données. documentation pour cette méthode ne donne aucun exemple sur la façon d'exécuter une requête paramétrée.

Comment spécifier correctement les paramètres ?

334voto

Robert te Kaat Points 381

Essayez ça :

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

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

3 votes

C'est la réponse qui devrait être marquée comme correcte. La réponse ci-dessus est sujette à des attaques et ne correspond pas aux meilleures pratiques.

10 votes

@Min, la réponse acceptée n'est pas plus sujette aux attaques que cette réponse. Vous pensiez peut-être qu'elle utilisait string.Format - ce n'est pas le cas.

1 votes

Ceci devrait être marqué comme réponse ! C'est la seule et unique réponse correcte car elle fonctionne avec DateTime.

232voto

jessegavin Points 20854

Il s'avère que ça marche.

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

15 votes

Cela fonctionnera, mais ce mécanisme permet les injections SQL et empêche également la base de données de réutiliser un plan d'exécution lorsque l'instruction réapparaît mais avec des valeurs différentes.

102 votes

@GregB Je ne pense pas que vous ayez raison. J'ai testé qu'il ne me permet pas, par exemple, de mettre fin prématurément à une chaîne littérale. De plus, j'ai examiné le code source et j'ai constaté qu'il utilise DbCommand.CreateParameter pour transformer toutes les valeurs brutes en paramètres. Donc pas d'injection SQL, et une invocation de méthode succincte.

7 votes

@JoshGallagher Oui, vous avez raison. Je pensais à un scénario de string.Format en assemblant tout ça.

74voto

Will Brown Points 311

Vous pouvez soit :

1) Passer des arguments bruts et utiliser la syntaxe {0}. Par exemple

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

2) Passer les arguments de la sous-classe DbParameter et utiliser la syntaxe @ParamName.

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

Si vous utilisez la première syntaxe, EF va en fait envelopper vos arguments avec les classes DbParamater, leur attribuer des noms, et remplacer {0} par le nom du paramètre généré.

La première syntaxe est préférable car il n'est pas nécessaire d'utiliser une fabrique ou de savoir quel type de DbParamater créer (SqlParameter, OracleParamter, etc.).

7 votes

Upvoted pour avoir mentionné que la syntaxe {0} est agnostique aux bases de données. "... vous n'avez pas [sic] besoin d'utiliser une fabrique ou de savoir quel type de DbParamaters [sic] créer..."

0 votes

Le scénario 1 est déprécié au profit d'une version interpolée. L'équivalent est maintenant : DbContext.Database.ExecuteSqlInterpolated($"StoredProcedureName {paramName}") ;

23voto

Ryan M Points 390

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

1 votes

Dieu merci, personne n'utilise Oracle. Enfin, pas volontairement ! EDIT : Toutes mes excuses pour la blague tardive ! EDIT : Excusez-nous pour la mauvaise blague !

19voto

Ladislav Mrnka Points 218632

Essayez ceci (édité) :

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

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

0 votes

Lorsque je fais cela, j'obtiens l'erreur suivante : "Il n'existe pas de correspondance entre le type d'objet System.Data.Objects.ObjectParameter et un type natif de fournisseur géré connu."

0 votes

Désolé, je me suis trompé. Utilisez DbParameter.

7 votes

DbParameter est abstrait. Vous devrez utiliser SqlParameter ou utiliser un DbFactory pour créer un DbParameter.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X