Подтвердить что ты не робот

Можно назвать имена держателей параметров ODBC?

Я сделал некоторые поиски и не нашел окончательного ответа на мои вопросы.

Есть ли способ определить, какой ? в SQL-запросе принадлежит какой параметр? Например, мне нужно выполнить что-то вроде этого:

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

Тот же запрос в ODBC:

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

Есть ли способ сообщить команде ODBC, какой параметр, который помимо загрузки параметров дважды для каждого значения?

Я подозреваю, что нет возможности использовать перспективу у более опытных программистов ODBC.

EDIT: драйвер ODBC, который я использую, является драйвером BBj ODBC.

4b9b3361

Ответ 1

В MSDN явно указано, что вы не можете назвать параметры, которые являются единственным способом "сообщить команде ODBC, какой параметр является".

Хотя документация может порождать путаницу:

От MSDN, класс OdbcParameter:

Если для параметра CommandType установлено значение "Текст", поставщик данных .NET Framework для ODBC не поддерживает передачу именованных параметров в оператор SQL или хранимую процедуру, называемую OdbcCommand. В любом из этих случаев используйте знак вопроса (?).

Порядок, в котором объекты OdbcParameter добавляются в OdbcParameterCollection, должен непосредственно соответствовать позиции заполнителя вопросительного знака для параметра в тексте команды.

Из вышесказанного кажется, что если CommandType не настроен на Text, возможно, вы можете использовать именованные параметры, но, к сожалению, вы не можете:

От MSDN, свойство OdbcCommand.CommandType:

Если для свойства CommandType установлено значение StoredProcedure, вы должны установить для свойства CommandText полный синтаксис вызова ODBC. Затем команда выполняет эту хранимую процедуру при вызове одного из методов Execute (например, ExecuteReader или ExecuteNonQuery).

Поставщик данных .NET Framework для ODBC не поддерживает передачу именованных параметров в оператор SQL или в хранимую процедуру, называемую OdbcCommand. В любом из этих случаев используйте знак вопроса (?) Placeholder...

Ответ 2

Спасибо, Том за вашу Идею и ваш код.
Однако код не работал правильно в моем тесте.
Поэтому я написал более простое (и, по крайней мере, в моем тестировании) решение для замены именованных параметров позиционными параметрами (где? Вместо имени):

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

Я не мог заставить его использовать именованные параметры - только позиционные параметры. Вы можете добавить все параметры, которые вы хотите, как показано ниже, но вы должны добавить значения в порядок.

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

Как видно из вышесказанного, имена параметров не имеют значения и не используются. Вы даже можете назвать их все равно, если хотите или еще лучше, оставьте имена параметров пустыми "".

Ответ 4

Я знаю, что при использовании ODBC Oracle Rdb я не могу использовать имя владельца места и должен использовать '?'; который я нахожу крайне раздражающим.

Ответ 5

Мне нужно было написать код, который обрабатывает именованные параметры для порядковых параметров с вопросительным знаком. Моя потребность была в OleDb вместо Odbc... но я уверен, что это сработает для вас, если вы измените типы.

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 [email protected] or [email protected] or [email protected]";
                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, "?");
            }
        }
    }
}

Ответ 6

Вот короткое решение этой проблемы: fooobar.com/info/152525/...

Я написал этот код для оболочки ODBC OpenEdge (Progress). Класс DatabaseAdapter - это оболочка и здесь не отображается.

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

Класс полезности для сортировки

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

Если именованный параметр последний в строке - вам нужно добавить пробел. например "SELECT * FROM tab WHERE col = @mycol" должен "SELECT * FROM tab WHERE col = @mycol "