web-dev-qa-db-fra.com

Quand "SqlDbType" et "size" doivent-ils être utilisés lors de l'ajout de paramètres SqlCommand?

Il y a une question connexe à cela:

Quelle est la meilleure méthode pour passer des paramètres à SQLCommand?

Mais je veux savoir quelles sont les différences et s'il y a des problèmes avec les différentes manières.

J'utilise généralement une structure comme celle-ci:

using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand(SQL, conn))
{
     cmd.CommandType = CommandType.Text;
     cmd.CommandTimeout = Settings.Default.reportTimeout;
     cmd.Parameters.Add("type", SqlDbType.VarChar, 4).Value = type;

     cmd.Connection.Open();

     using (SqlDataAdapter adapter = new SqlDataAdapter(cmd))
     {
         adapter.Fill(ds);
     }
      //use data                    
}

Maintenant, il existe plusieurs façons d'ajouter les paramètres cmd et je me demande laquelle est la meilleure:

cmd.Parameters.Add("@Name", SqlDbType.VarChar, 20).Value = "Bob";
cmd.Parameters.Add("@Name", SqlDbType.VarChar).Value = "Bob";
cmd.Parameters.Add("@Name").Value = "Bob";
cmd.Parameters.AddWithValue("@Name", "Bob");

Ayant la longueur du champ au passage des varchars, je suppose que ce n'est pas préférable car c'est une valeur magique qui peut être modifiée plus tard dans la base de données. Est-ce correct? Cela provoque-t-il un problème en passant un varchar de cette manière (performances ou autre), je suppose qu'il est par défaut varchar (max) ou l'équivalent de la base de données. Je suis raisonnablement heureux que cela fonctionnera.

La partie qui me préoccupe le plus est la perte de l'énumération SqlDbType si j'utilise les troisième ou quatrième options énumérées ci-dessus, je ne fournis aucun type. Y a-t-il des cas où cela ne fonctionnera pas? Je peux imaginer des problèmes avec varchar mal converti en char ou vice versa ou peut-être des problèmes avec décimal en argent ...

En termes de base de données, le type de champ, je dirais, est beaucoup moins susceptible de changer que la longueur, est-ce que cela vaut la peine d'être conservé?

41
PeteT

D'après mon expérience, je m'assurerais de faire ces choses:

  • assurez-vous que c'est vous qui définissez le type de données pour le paramètre. ADO.NET fait un travail décent pour deviner, mais dans certains cas, il peut être très difficile - j'éviterais donc cette méthode:

    cmd.Parameters.Add("@Name").Value = "Bob";
    cmd.Parameters.AddWithValue("@Name", "Bob");
    

    Laisser ADO.NET deviner le type du paramètre par la valeur passée est délicat, et s'il est désactivé pour une raison quelconque, ce sont des bogues vraiment difficiles à suivre et à trouver! Imaginez ce qui se passe lorsque vous passez dans un DBNull.Value - quel type de données ADO.NET doit-il choisir pour cela?

    Soyez explicite - dites quel type vous voulez!

  • si vous utilisez des paramètres de chaîne, assurez-vous de définir explicitement la longueur - donc j'éviterais également cette méthode:

    cmd.Parameters.Add("@Name", SqlDbType.VarChar).Value = "Bob";
    

    Si vous ne fournissez pas de longueur, ADO.NET peut prendre par défaut une valeur arbitraire, ou la longueur de la chaîne transmise en tant que valeur, ou autre chose - vous n'êtes jamais tout à fait sûr. Et si votre longueur ne correspond pas à ce que le proc stocké attend vraiment, vous pourriez voir la conversion et d'autres surprises désagréables. Donc, si vous définissez une chaîne, définissez également sa longueur!

Donc, dans votre cas, la seule approche qui fonctionne vraiment pour moi est celle-ci:

cmd.Parameters.Add("@Name", SqlDbType.VarChar, 20).Value = "Bob";

car il a) définit explicitement le type de données à utiliser et b) définit explicitement la longueur de la chaîne.

56
marc_s

En ajoutant le type, vos demandes sont plus susceptibles d'améliorer les performances en utilisant un plan de requête mis en cache.

Voici une citation de MSDN:

Les commandes paramétrées peuvent également améliorer les performances d'exécution des requêtes, car elles aident le serveur de base de données à faire correspondre précisément la commande entrante avec un plan de requête mis en cache approprié.

Plus à lire dans Mise en cache et réutilisation du plan d'exécution .

6
StefanE