System.AccessViolationException - клиентские инструменты Oracle

Framework Version: v4.0.30319 
Description: The process was terminated due to an unhandled exception.
Exception Info: System.AccessViolationException
Stack:
  at Oracle.DataAccess.Client.OracleParameter.SetStatus(Int32)
  at Oracle.DataAccess.Client.OracleParameter.PreBind(Oracle.DataAccess.Client.OracleConnection, IntPtr, Int32, Boolean)
  at Oracle.DataAccess.Client.OracleCommand.ExecuteNonQuery()

Мое приложение падает с этим исключением. контекст: мы пытаемся выполнить хранимую процедуру, которая принимает два параметра, мы используем привязку имени для параметров в тексте команды.

Пример:

OraCommand.CommandText = "begin LOAD_UTILS.TRUNCATE_TABLE(:a1,:a2); end;"
OraCommand.Parameters.Add(New OracleParameter("a1", OracleDbType.Varchar2, 1000))
OraCommand.Parameters(0).Direction = ParameterDirection.Input
OraCommand.Parameters(0).Value = params(2)
OraCommand.Parameters.Add(New OracleParameter("a2", OracleDbType.Varchar2, 1000))
OraCommand.Parameters(1).Direction = ParameterDirection.Input
OraCommand.Parameters(1).Value = params(3)

Странность, которую я заметил, состоит в том, что мы выполняем эти операторы в цикле for для определенного числа повторных попыток, если в случае каких-либо ошибок OraCommand является переменной экземпляра, поэтому сбор параметров не очищается.

На итерации № 1: добавляются параметры a1, a2
На итерации № 2: первые два параметра уже есть, и мы снова добавляем параметры с именами a1 и a2. ...

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

2 ответа

Вы используете ODP.Net, и, как это работает, API.Net C# являются просто оберткой для предоставления своего уровня обслуживания в C, который взаимодействует с OCI (интерфейсами Oracle Call), в основном исключение нарушения доступа происходит из их уровня обслуживания или OCI. Поскольку в управляемом коде (.Net C#) наличие Нарушения прав доступа (AV) нереально, CLR этого не допускает. Более простой способ отладить проблему - использовать Windbg, загрузить символы, и он укажет вам точный метод, вызывающий проблему, который будет неуправляемым кодом, но проблема в том, что у вас будет версия выпуска с максимально открытой Символы, которые не очень помогают, другой вариант - опубликовать проблему с кодом в Oracle Technet, где разработчик ODP.Net может предоставить обходной путь и исправить это. Однако до этого, на мой взгляд, есть определенные проблемы с вашим кодом:

В цикле следующие строки будут добавлять новый параметр a1 и a2 каждый раз

OraCommand.Parameters.Add(New OracleParameter("a1", OracleDbType.Varchar2, 1000))
OraCommand.Parameters.Add(New OracleParameter("a2", OracleDbType.Varchar2, 1000))

Такое поведение вы ожидаете, так как только после создания новых параметров вы устанавливаете значение и направление в индексах 0 и 1, что является одинаковым каждый раз, в каждой итерации вы добавляете два новых параметра в объект OracleCommand и где-то, что портит внутреннюю структуру, поскольку то, что вы делаете, неверно. Правильным способом будет следующий код в цикле:

OracleParameter A1 = OracleParameter("a1", OracleDbType.Varchar2, 1000)
A1.Direction = ParameterDirection.Input
A1.Value = params[2]
OracleCommand.Parameters[0] = A1;

OracleParameter A2 = OracleParameter("a2", OracleDbType.Varchar2, 1000)
A1.Direction = ParameterDirection.Input
A1.Value = params[3]
OracleCommand.Parameters[1] = A2;

Фактически, еще одна странная вещь в вашем коде - это доступ к коллекции, такой как массив, со следующим кодом:

OraCommand.Parameters(0).Value = params(2)

Это невозможно в C#, вы должны использовать квадратную скобку [], на мой взгляд, вы должны использовать VB.Net, так как даже вы new это не правильно, это не New в C#

@Mrinal Kamboj Вы правы, код находится в VB.NET; Возникла исключительная ситуация при попытке выполнить ExecuteNonQuery. Я попробовал WinDbg, и это то, что он дает:

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