web-dev-qa-db-fra.com

Ajout de paramètres à IDbCommand

Je crée une petite fonction d'assistance pour renvoyer un DataTable. Je souhaite travailler avec tous les fournisseurs pris en charge par ADO.Net. J'ai donc pensé à tout faire en utilisant IDbCommand ou DbCommand si possible.

J'ai atteint une pierre d'achoppement avec le code suivant:

    private static DataTable QueryImpl(ref IDbConnection conn, String SqlToExecute, CommandType CommandType, Array Parameters)
    {
        SetupConnection(ref conn);
        // set the capacity to 20 so the first 20 allocations are quicker...
        DataTable dt = new DataTable();
        using (IDbCommand cmd = conn.CreateCommand())
        {
            cmd.CommandText = SqlToExecute;
            cmd.CommandType = CommandType;
            if (Parameters != null && Parameters.Length > 0)
            {
                for (Int32 i = 0; i < Parameters.Length; i++)
                {
                    cmd.Parameters.Add(Parameters.GetValue(i));
                }
            }
            dt.Load(cmd.ExecuteReader(), LoadOption.OverwriteChanges);
        }
        return dt;
    }

Lorsque ce code est exécuté, je reçois une InvalidCastException qui indique ce qui suit:

SqlParameterCollection accepte uniquement les objets de type SqlParameter non NULL, pas les objets String.

Le code tombe sur la ligne:

cmd.Parameters.Add(Parameters.GetValue(i));

Des idées? 

Toute amélioration du code ci-dessus est appréciée.


Solution actuelle: 

    private static readonly Regex regParameters = new Regex(@"@\w+", RegexOptions.Compiled);
    private static DataTable QueryImpl(ref DbConnection conn, String SqlToExecute, CommandType CommandType, Object[] Parameters)
    {
        SetupConnection(ref conn);
        DataTable dt = new DataTable();
        using (DbCommand cmd = conn.CreateCommand())
        {
            cmd.CommandText = SqlToExecute;
            cmd.CommandType = CommandType;
            if (Parameters != null && Parameters.Length > 0)
            {
                MatchCollection cmdParams = regParameters.Matches(cmd.CommandText);
                List<String> param = new List<String>();
                foreach (var el in cmdParams)
                {
                    if (!param.Contains(el.ToString()))
                    {
                        param.Add(el.ToString());
                    }
                }
                Int32 i = 0;
                IDbDataParameter dp;
                foreach (String el in param)
                {
                    dp = cmd.CreateParameter();
                    dp.ParameterName = el;
                    dp.Value = Parameters[i++];
                    cmd.Parameters.Add(dp);
                }
            }
            dt.Load(cmd.ExecuteReader(), LoadOption.OverwriteChanges);
        }
        return dt;
    } 

Merci pour les idées/liens, etc. :)

39
Stuart Blackler

Je crois que IDbCommand a une méthode CreateParameter ():

var parameter = command.CreateParameter();
parameter.ParameterName = "@SomeName";
parameter.Value = 1;

command.Parameters.Add(parameter);
76
Dismissile

Vous pouvez ajouter le code de la réponse acceptée à une méthode d'extension:

public static class DbCommandExtensionMethods
{
    public static void AddParameter (this IDbCommand command, string name, object value)
    {
        var parameter = command.CreateParameter();
        parameter.ParameterName = name;
        parameter.Value = value;
        command.Parameters.Add(parameter);
    }
}
23
onestarblack

Je sais que ce n’est pas ce que vous demandez, mais j’ai une solution beaucoup plus simple et plus robuste à offrir.

La bibliothèque Microsoft Patterns and Practices comprend un bloc Application d'accès aux données incroyablement puissant et facile à utiliser. Un exemple pour exécuter une procédure stockée et renvoyer un ensemble de données est présenté ci-dessous à partir de notre code actuel:

 object[] ParameterValues = new object[] {"1",DateTime.Now, 12, "Completed", txtNotes.Text};
 Database db = DatabaseFactory.CreateDatabase("ConnectionStringName");
 DataSet ds =  = db.ExecuteDataSet("StoredProcName", ParameterValues);

Peu importe que la connexion soit OleDb, ODBC, etc. ConnectionStringName dans la première ligne de code est simplement le nom de Consternating tel que défini dans le fichier .config. Vous transmettez un nom de chaîne de connexion, un nom de proc stocké et un tableau d’objets, qui constituent les paramètres . Ceci n’est qu’une des nombreuses fonctions utiles disponibles.

Vous obtiendrez tout ce que vous essayez de construire et plus encore.

Le site officiel est ici: http://msdn.Microsoft.com/en-us/library/ff648951.aspx

Pour vous épargner quelques recherches, vous trouverez la documentation sur les classes de données à l'adresse suivante: http://msdn.Microsoft.com/en-us/library/Microsoft.practices.enterpriselibrary.data(PandP.50).aspx

(et c'est gratuit de Microsoft, et mis à jour régulièrement.)

2
David

Cette réponse a un but légèrement plus spécifique que ce que vous faites, mais en me basant sur la réponse de @Dismissile , j'ai utilisé une variable Dictionary pour fournir le nom et la valeur du paramètre à une boucle foreach dans mon projet personnel. 

using( IDbCommand dbCommand = dbConnection.CreateCommand() )
{
    dbCommand.CommandText = Properties.Settings.Default.UpdateCommand;
    Dictionary<string,object> values = new Dictionary<string,object>()
    {
        {"@param1",this.Property1},
        {"@param2",this.Property2},
        // ...
    };
    foreach( var item in values )
    {
        var p = dbCommand.CreateParameter();
        p.ParameterName = item.Key;
        p.Value = item.Value;
        dbCommand.Parameters.Add(p);
    }
}
0
Drew Chapin

Votre paramètre Parameters doit être de type IDataParameter[] et, étant donné le texte d'erreur, l'implémentation concrète doit être de type SqlParameter[].

Si vous souhaitez conserver votre signature, vous aurez besoin d’une usine pour obtenir l’application concrète nécessaire.

0
Austin Salonen