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