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, и это то, что он дает: