ORA-01008 со всеми связанными переменными

Я использую System.Data.OracleClient который выполняет привязку параметров по имени и проверяет, что CommandText и Parameters синхронизированы:

    public string CommandText { get; set; }
    public IEnumerable<OracleParameter> Parameters { get; set; }

    private void VerifyThatAllParametersAreBound()
    {
        var variableNames = Regex.Matches(CommandText, ":\\w+")
            .Cast<Match>().Select(m => m.Value).ToArray();
        var parameteterNames = Parameters.Select(p => p.ParameterName).ToArray();

        var unboundVariables = variableNames.Except(parameteterNames).ToArray();
        if (unboundVariables.Length > 0)
        {
            throw new Exception("Variable in CommandText missing parameter: "
                + string.Join(", ", unboundVariables) + ".");
        }

        var unboundParameters = parameteterNames.Except(variableNames).ToArray();
        if (unboundParameters.Length > 0)
        {
            throw new Exception("Parameter that is not used in CommandText: "
                + string.Join(", ", unboundParameters) + ".");
        }
    }

Еще один запрос кидает ORA-01008: not all variables bound, При ручной вставке значений параметров в ошибочный CommandText выполняется запрос, поэтому значения CommandText и Parameters должны быть в порядке. Я использую: в качестве префикса как для переменных, так и для имен параметров, и это работает для других запросов.

Как я могу определить причину этого исключения?

3 ответа

Решение

Ошибка не указала DBNull.Value для нулевых значений. Так

new OracleParameter(":Foo", item.Foo)

пришлось поставить с

item.Foo == null 
    ? new OracleParameter(":Foo", DBNull.Value) 
    : new OracleParameter(":Foo", item.Foo)

Я думаю, что раньше он работал с ODT.NET без нулевых проверок, но не подтвердил это. По-видимому System.Data.OracleClient сбрасывает параметры с нулевым значением.

Если вы передадите null в качестве значения параметра, вы получите "Не все переменные связаны". Если вы передадите DBNull.Value, вы получите ошибку времени выполнения где-то в OracleClient. Чтобы передать NULL, используйте string.Empty, OracleClient преобразует его в NULL для любого типа базы данных.

Если у вас более одного параметра, вам необходимо установить для BindByName значение true. Например:

OracleCommand cmd = con.CreateCommand();

cmd.BindByName = true;

cmd.Parameters.Add(new OracleParameter("parameter1", parameter1));
cmd.Parameters.Add(new OracleParameter("parameter2", parameter2));

Я считаю, что Microsoft отказалась от OracleClient как часть ADO.NET около 2 лет назад.

Вы можете рассмотреть возможность использования компонентов доступа к данным Oracle (ODAC odp.net). Легко построить (и проверить количество) параметров с помощью класса OracleParameter. Установки и установки документов можно найти здесь. О, вы также можете получить поддержку их Entity Framework (и LINQ) (все еще бета, я думаю?).

Что-то серьезно рассмотреть в любом случае.

Основываясь на приведенных выше ответах и ​​комментариях, я убедился в следующем, чтобы решить эту проблему:

  • параметры привязываются в том же порядке, в котором они появляются в запросе
  • указан тип параметра
  • Если одно и то же значение параметра требуется более одного раза в SQL, назовите каждый параметр по-разному в SQL (не уверен, требуется ли это)

    OracleParameter[] или abc" }, новый OracleParameter{ ParameterName = "date1", OracleDbType = OracleDbType.Date, Value = myDate } }; SomeFunction(sqlQuery или clParams.ToList());

Другие вопросы по тегам