Est-ce que les porte-paramètres ODBC peuvent être nommés?

j'ai fait quelques recherches et n'ai pas trouvé de réponse définitive à mes questions.

est-il possible de définir quel ? dans une requête SQL appartient à quel paramètre?

Par exemple, je dois effectuer quelque chose comme ceci:

SELECT * FROM myTable WHERE myField = @Param1 OR myField2 = @Param1 
       OR myField1 = @Param2 OR myField2 = @Param2

la même requête dans ODBC est:

SELECT * FROM myTable WHERE myField = ? or myField2 = ? or myField1 = ? 
       or myField2 = ?

est-il possible de dire à la commande ODBC quel paramètre est en plus des paramètres de chargement en deux fois pour chaque valeur?

je soupçonne qu'il n'y a pas mais pourrait utiliser la perspective de programmeurs ODBC plus expérimentés.

EDIT : le pilote ODBC que j'utilise est un pilote BBj ODBC.

13
demandé sur Jonathan Leffler 2011-06-14 05:23:34

6 réponses

Dans MSDN, il est explicitement dit que vous ne pouvez pas nommer les paramètres qui est la seule façon de "raconter l'ODBC de commande de paramètre qui est qui".

bien que la documentation puisse générer un peu de confusion:

à Partir de MSDN, OdbcParameter Classe :

lorsque le type de commande est défini au texte, le fournisseur de données .net Framework pour ODBC ne supporte pas la transmission des paramètres nommés à un SQL déclaration ou à une procédure stockée appelée par une OdbcCommand. Dans ces deux cas, le point d'interrogation (?) réservé.

l'ordre dans lequel les objets OdbcParameter sont ajoutés à la section Odbcparameterercollection doit correspondre directement à la position de l'espace réservé aux points d'interrogation pour le paramètre dans le texte de commande.

à partir de ce qui précède, il semble suggérer que lorsque CommandType n'est pas défini au texte peut-être Pouvez-vous utiliser les paramètres nommés, mais malheureusement vous ne pouvez pas:

From MSDN, OdbcCommand.Propriété De Type De Commande :

lorsque la propriété CommandType est définie à StoredProcedure, vous devez définir la propriété CommandText à la syntaxe D'appel ODBC complète. La commande exécute alors cette procédure stockée lorsque vous appelez l'une des méthodes Execute (par exemple, ExecuteReader ou ExecuteNonQuery).

le .net Framework Data Provider pour ODBC ne supporte pas la transmission de paramètres nommés à une instruction SQL ou à une procédure stockée appelée par une OdbcCommand. Dans ces deux cas, le point d'interrogation (?) réservé...

11
répondu Rui 2013-01-17 12:18:56

Merci Tom pour votre idée et votre code.

Cependant, le code ne fonctionnait pas correctement dans mon test.

J'ai donc écrit une solution plus simple (et au moins dans mes tests) pour remplacer les paramètres nommés par des paramètres de position (où ? est utilisé à la place du nom):

public static class OdbcCommandExtensions
{
    public static void ConvertNamedParametersToPositionalParameters(this OdbcCommand command)
    {
        //1. Find all occurrences parameters references in the SQL statement (such as @MyParameter).
        //2. Find the corresponding parameter in the command's parameters list.
        //3. Add the found parameter to the newParameters list and replace the parameter reference in the SQL with a question mark (?).
        //4. Replace the command's parameters list with the newParameters list.

        var newParameters = new List<OdbcParameter>();

        command.CommandText = Regex.Replace(command.CommandText, "(@\w*)", match =>
        {
            var parameter = command.Parameters.OfType<OdbcParameter>().FirstOrDefault(a => a.ParameterName == match.Groups[1].Value);
            if (parameter != null)
            {
                var parameterIndex = newParameters.Count;

                var newParameter = command.CreateParameter();
                newParameter.OdbcType = parameter.OdbcType;
                newParameter.ParameterName = "@parameter" + parameterIndex.ToString();
                newParameter.Value = parameter.Value;

                newParameters.Add(newParameter);
            }

            return "?";
        });

        command.Parameters.Clear();
        command.Parameters.AddRange(newParameters.ToArray());
    }
}
3
répondu David Liebeherr 2014-02-21 05:04:03

Je n'ai pas pu le faire utiliser les paramètres nommés - seulement les paramètres de position. Vous pouvez ajouter tous les paramètres que vous souhaitez comme ci-dessous, mais vous devez ajouter les valeurs dans l'ordre.

SELECT * FROM myTable WHERE myField = ? or myField1 = ? or myField2 = ? 
       or myField2 = ?
myOdbcCommand.Parameters.AddWithValue("DoesNotMatter", val1); //myField
myOdbcCommand.Parameters.AddWithValue("WhatYouPutHere", val2); //myField1
myOdbcCommand.Parameters.AddWithValue("DoesNotMatter", val3); //myField2
myOdbcCommand.Parameters.AddWithValue("WhatYouPutHere", val4); //myField2

comme vous pouvez le voir ci-dessus, les noms de paramètres n'ont pas d'importance et ne sont pas utilisés. Vous pouvez même les nommer tous les mêmes si vous voulez ou mieux encore, laisser les noms de param vides "" .

3
répondu goku_da_master 2014-10-24 15:41:32

je sais que lors de L'utilisation D'Oracle Rdb ODBC, Je ne peux pas utiliser le nom des titulaires de place et doivent utiliser '?"qui je trouve extrêmement ennuyeux.

0
répondu Richard Schneider 2011-06-14 01:26:33

j'ai eu besoin d'écrire un code qui gère la conversion des paramètres nommés en paramètres ordinaux avec le point d'interrogation. Mon besoin était avec OleDb au lieu D'Odbc... mais je suis sûr que ça marcherait pour vous si vous changiez les types.

using System;
using System.Collections.Generic;
using System.Data.OleDb;
using System.Linq;
using System.Text.RegularExpressions;

namespace OleDbParameterFix {
    static class Program {
        [STAThread]
        static void Main() {
            string connectionString = @"provider=vfpoledb;data source=data\northwind.dbc";
            using (var connection = new OleDbConnection(connectionString))
            using (var command = connection.CreateCommand()) {
                command.CommandText = "select count(*) from orders where orderdate=@date or requireddate=@date or shippeddate=@date";
                command.Parameters.Add("date", new DateTime(1996, 7, 11));

                connection.Open();

                OleDbParameterRewritter.Rewrite(command);
                var count = command.ExecuteScalar();

                connection.Close();
            }
        }
    }

    public class OleDbParameterRewritter {
        public static void Rewrite(OleDbCommand command) {
            HandleMultipleParameterReferences(command);
            ReplaceParameterNamesWithQuestionMark(command);
        }

        private static void HandleMultipleParameterReferences(OleDbCommand command) {
            var parameterMatches = command.Parameters
                                          .Cast<OleDbParameter>()
                                          .Select(x => Regex.Matches(command.CommandText, "@" + x.ParameterName))
                                          .ToList();

            // Check to see if any of the parameters are listed multiple times in the command text. 
            if (parameterMatches.Any(x => x.Count > 1)) {
                var newParameters = new List<OleDbParameter>();

                // order by descending to make the parameter name replacing easy 
                var matches = parameterMatches.SelectMany(x => x.Cast<Match>())
                                              .OrderByDescending(x => x.Index);

                foreach (Match match in matches) {
                    // Substring removed the @ prefix. 
                    var parameterName = match.Value.Substring(1);

                    // Add index to the name to make the parameter name unique. 
                    var newParameterName = parameterName + "_" + match.Index;
                    var newParameter = (OleDbParameter)((ICloneable)command.Parameters[parameterName]).Clone();
                    newParameter.ParameterName = newParameterName;

                    newParameters.Add(newParameter);

                    // Replace the old parameter name with the new parameter name.   
                    command.CommandText = command.CommandText.Substring(0, match.Index)
                                            + "@" + newParameterName
                                            + command.CommandText.Substring(match.Index + match.Length);
                }

                // The parameters were added to the list in the reverse order to make parameter name replacing easy. 
                newParameters.Reverse();
                command.Parameters.Clear();
                newParameters.ForEach(x => command.Parameters.Add(x));
            }
        }

        private static void ReplaceParameterNamesWithQuestionMark(OleDbCommand command) {
            for (int index = command.Parameters.Count - 1; index >= 0; index--) {
                var p = command.Parameters[index];
                command.CommandText = command.CommandText.Replace("@" + p.ParameterName, "?");
            }
        }
    }
}
0
répondu Tom Brothers 2011-11-19 15:49:47

Voici une courte solution pour le post: https://stackoverflow.com/a/21925683/2935383

j'ai écrit ce code pour un emballage ODBC OpenEdge (Progress). La classe DatabaseAdapter est ce wrapper et ne sera pas montrée ici.

string _convertSql( string queryString, List<DatabaseAdapter.Parameter> parameters, 
                    ref List<System.Data.Odbc.OdbcParameter> odbcParameters ) {
    List<ParamSorter> sorter = new List<ParamSorter>();
    foreach (DatabaseAdapter.Parameters item in parameters) {
        string parameterName = item.ParameterName;
        int indexSpace = queryString.IndexOf(paramName + " "); // 0
        int indexComma = queryString.IndexOf(paramName + ","); // 1

        if (indexSpace > -1){
            sorter.Add(new ParamSorter() { p = item, index = indexSpace, type = 0 });
        }
        else {
            sorter.Add(new ParamSorter() { p = item, index = indexComma, type = 1 });
        }
    }

    odbcParameters = new List<System.Data.Odbc.OdbcParameter>();
    foreach (ParamSorter item in sorter.OrderBy(x => x.index)) {
        if (item.type == 0) { //SPACE
            queryString = queryString.Replace(item.p.ParameterName + " ", "? ");
        }
        else { //COMMA
            queryString = queryString.Replace(item.p.ParameterName + ",", "?,");
        }
        odbcParameters.Add(
                new System.Data.Odbc.OdbcParameter(item.p.ParameterName, item.p.Value));
    }
}

Classe D'utilité pour le tri

class ParamSorter{
    public DatabaseAdapter.Parameters p;
    public int index;
    public int type;
}

Si le paramètre nommé le dernier de la chaîne, vous devez ajouter un espace. par exemple "SELECT * FROM tab WHERE col = @mycol" doit "SELECT * FROM tab WHERE col = @mycol "

0
répondu raiserle 2017-05-23 11:53:14