37 votes

Avantages et inconvénients de l'utilisation de SqlCommand Préparer en C #?

Quand je lisais les livres pour apprendre le C# (peut-être quelques vieux Visual Studio 2005 livres) que j'ai rencontré des conseils de toujours utiliser SqlCommand.Prepare chaque fois que j'execute SQL appel (si son " un SELECT/UPDATE ou INSERT sur SQL SERVER 2005/2008) et j'ai passer des paramètres à elle. Mais est-ce vraiment le cas?

  1. Faut-il le faire à chaque fois? Ou tout simplement, parfois?

  2. Il importe peu de savoir si c'est un paramètre passé cinq ou vingt?

  3. Ce boost devrait-elle fournir le cas échéant? Serait-il être perceptible à tous (j'ai été en utilisant SqlCommand.Prepare ici et a sauté là-bas et jamais eu de problèmes ou de différences notables).

Pour l'amour de la question, c'est mon habitude de code que j'utilise, mais c'est plus une question d'ordre général.

public static decimal pobierzBenchmarkKolejny(string varPortfelID, DateTime data, decimal varBenchmarkPoprzedni, decimal varStopaOdniesienia) {
    const string preparedCommand = @"SELECT [dbo].[ufn_BenchmarkKolejny](@varPortfelID, @data, @varBenchmarkPoprzedni,  @varStopaOdniesienia) AS 'Benchmark'";
    using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetailsDZP)) //if (varConnection != null) {
    using (var sqlQuery = new SqlCommand(preparedCommand, varConnection)) {
        sqlQuery.Prepare();
        sqlQuery.Parameters.AddWithValue("@varPortfelID", varPortfelID);
        sqlQuery.Parameters.AddWithValue("@varStopaOdniesienia", varStopaOdniesienia);
        sqlQuery.Parameters.AddWithValue("@data", data);
        sqlQuery.Parameters.AddWithValue("@varBenchmarkPoprzedni", varBenchmarkPoprzedni);
        using (var sqlQueryResult = sqlQuery.ExecuteReader())
            if (sqlQueryResult != null) {
                while (sqlQueryResult.Read()) {

                }
            }
    }
}

Précisions supplémentaires:

Si je déplace sqlQuery.Prepare() comme dans le code ci-dessous exception est levée que la taille doit être explicitement déclarée, qui, fondamentalement, m'amène à penser que le fait d'avoir sqlQuery.Prepare() comme première rend inutile? Quelqu'un peut-il montrer la bonne utilisation de l'aide de mon exemple?

public static decimal pobierzBenchmarkKolejny(string varPortfelID, DateTime data, decimal varBenchmarkPoprzedni, decimal varStopaOdniesienia) {
    const string preparedCommand = @"SELECT [dbo].[ufn_BenchmarkKolejny](@varPortfelID, @data, @varBenchmarkPoprzedni,  @varStopaOdniesienia) AS 'Benchmark'";
    using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetailsDZP)) //if (varConnection != null) {
    using (var sqlQuery = new SqlCommand(preparedCommand, varConnection)) {

        sqlQuery.Parameters.AddWithValue("@varPortfelID", varPortfelID);
        sqlQuery.Parameters.AddWithValue("@varStopaOdniesienia", varStopaOdniesienia);
        sqlQuery.Parameters.AddWithValue("@data", data);
        sqlQuery.Parameters.AddWithValue("@varBenchmarkPoprzedni", varBenchmarkPoprzedni);
        sqlQuery.Prepare();
        using (var sqlQueryResult = sqlQuery.ExecuteReader())
            if (sqlQueryResult != null) {
                while (sqlQueryResult.Read()) {

                }
            }
    }
}

Comment dois-je procéder? En ajoutant .taille à côté de paramètres et de faire varPortfel.Longueur si c'est une chaîne de caractères etc?

12voto

RandomBen Points 4012

À partir de la Documentation MSDN:

"Avant de vous appeler Préparer, spécifiez l' type de données de chaque paramètre dans la déclaration afin d'être préparé. Pour chaque paramètre qui a une longueur variable type de données, vous devez définir la Taille propriété à la taille maximale nécessaire. Préparer renvoie une erreur si ces les conditions ne sont pas remplies.

Si vous appelez une méthode Execute après l'appel de Préparer, de toute valeur du paramètre qui est supérieure à la valeur spécifié par la Taille de la propriété est automatiquement tronqué à l' d'origine spécifié la taille de la paramètres, et sans les erreurs de troncature sont retournés.

Les paramètres de sortie (que ce soit ou pas) il est spécifié par l'utilisateur de données type. Si vous spécifiez une longueur variable type de données, vous devez également spécifier l' Taille maximale."

En outre, "Si le CommandType la propriété est définie à TableDirect, Préparer ne fait rien. Si CommandType est fixé à StoredProcedure, l'appel à Préparer devrait réussir, ..."

Ce sont en général est utilisé pour s'assurer que l'utilisateur final n'est pas à l'aide d'une Injection SQL de la technique d'ajouter ou de supprimer des informations que vous ne voulez pas trop à partir de la base de données.

J'ai regardé dedans et découvrez cet article http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.prepare.aspx. Votre problème est que vous devez définir vos paramètres avant de vous lancer .Prepare() et puis définissez vos paramètres après l'exécution .Prepare(). Maintenant vous faites tous les deux avant de. Je voudrais essayer quelque chose comme ceci (Notez que je n'ai pas tester donc ma syntaxe peut-être un peu off).

public static decimal pobierzBenchmarkKolejny(string varPortfelID, DateTime data, decimal varBenchmarkPoprzedni, decimal varStopaOdniesienia) {
    const string preparedCommand = @"SELECT [dbo].[ufn_BenchmarkKolejny](@varPortfelID, @data, @varBenchmarkPoprzedni,  @varStopaOdniesienia) AS 'Benchmark'";
    using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetailsDZP)) //if (varConnection != null) {
    using (var sqlQuery = new SqlCommand(preparedCommand, varConnection)) {

        sqlQuery.Parameters.Add("@varPortfelID");
        sqlQuery.Parameters.Add("@varStopaOdniesienia");
        sqlQuery.Parameters.Add("@data");
        sqlQuery.Parameters.Add("@varBenchmarkPoprzedni");

        sqlQuery.Prepare();
        sqlQuery.ExecuteNonQuery();//This might need to be ExecuteReader()

        sqlQuery.Parameters[0].Value = varPortfelID;
        sqlQuery.Parameters[1].Value = varStopaOdniesienia;
        sqlQuery.Parameters[2].Value = data;
        sqlQuery.Parameters[3].Value = varBenchmarkPoprzedni;

        using (var sqlQueryResult = sqlQuery.ExecuteReader())
            if (sqlQueryResult != null) {
                while (sqlQueryResult.Read()) {

                }
            }
    }
}

7voto

James Points 7234

L'autre avantage est qu'en procédant ainsi, le plan de requête SQL est compilé, mis en cache et réutilisé . Ce n'est pas un gros problème si pour un faible volume d'appels à votre requête, mais si vous en avez beaucoup, il y a vraiment des avantages de performances significatifs à le faire.

4voto

user3051888 Points 21

De ma propre expérience: le gain de performances est TRÈS importante. Il y a quelques temps, j'ai travaillé sur un projet où nous avons utilisé notre propre mapping objet-relationnel. Nous avons utilisé l'immense base de données comme un magasin permanent de complexe sur le modèle objet, sur demande, des objets de chargement et de faiblesse de l'objet référencé par la vie en temps.

En utilisant les commandes préparées a été crucial pour le succès de cette application, car il est seul à le système réellement utilisable.

En d'autres termes: si vous exécuter de nombreuses commandes SQL - que sont exactement les mêmes ou ne diffèrent que dans les valeurs de paramètre, vous verrez énorme gain de performance.

Je n'ai pas de chiffres exacts, ou des liens, mais je peux témoigner de ma propre expérience.

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