Ошибка PL SQL в моем коде VB. Net, но не может быть воспроизведена в SQL Developer - PullRequest
0 голосов
/ 18 февраля 2020

ORA-06502: PL / SQL: цифра c или ошибка значения
ORA-06512: в «JOHN.GET_USERS_EMAIL», строка 7
ORA-06512: в строке 1

Когда я запускаю процедуру в SQL Developer и использую значения в моем приложении, она работает без каких-либо проблем. Когда я запускаю свой код VB. Net, я получаю исключение (показано выше)

Я не знаю, что я делаю неправильно. (Процедура Oracle была написана не мной, а другим лицом, которое здесь больше не работает).

Процедура в Oracle

create or replace PROCEDURE "GET_USERS_EMAIL" (
User_Email_P OUT VARCHAR,
Employee_P IN VARCHAR
)
As 
Begin
SELECT USER_EMAIL INTO User_Email_P FROM
EMPLOYEE
WHERE
USER_ID = Employee_P;
end; 

Код в VB. Net

Public Function Get_A_Users_Email(ByVal strEmpId As String) As String
    Try
        Dim rValue As String = ""
        Dim strSQL As String = "JOHN.GET_USERS_EMAIL"
        Dim cmd As OracleCommand = dba.CreateStoredProcCommand(strSQL)
        cmd.BindByName = True
        Dim oracleParameter(1) As OracleParameter
        oracleParameter(0) = New OracleParameter()
        oracleParameter(1) = New OracleParameter()
        strEmpId = UCase(strEmpId.Trim())

        With cmd
            oracleParameter(0) = cmd.Parameters.Add(name:="User_Email_P", dbType:=OracleDbType.Varchar2, direction:=ParameterDirection.Output)
            oracleParameter(1) = cmd.Parameters.Add(name:="Employee_P", dbType:=OracleDbType.Varchar2, val:=strEmpId, ParameterDirection.Input)

        End With

        dba.ExecuteScaler(cmd)

        If String.IsNullOrEmpty(cmd.Parameters("User_Email_P").Value.ToString) = True Then
            rValue = 0
        Else
            rValue = cmd.Parameters("User_Email_P").Value.ToString
        End If

        Return rValue
    Catch ex As Exception
        Dim Err As New App_Errors("App_Users", "Get_A_Users_Email", ex)
        Return Nothing
    End Try
End Function

Public Function ExecuteScaler(ByVal cmd As OracleCommand) As String
    ' the value tobe return ...
    Dim value As String = ""
    Dim oValue As Object
    Dim bValue As Boolean = False
    ' execute command ...
    Try
        ' open connection ...
        cmd.Connection.Open()
    Catch ex As Exception
        MsgBox("Unable to establish a connection to CFR database." & ex.ToString, MsgBoxStyle.Critical)
        Return value = ""
        Exit Function
    End Try
    Try

        ' execute command ... convert type in the case of return value null ...
        oValue = cmd.ExecuteScalar
        bValue = Convert.IsDBNull(oValue)
        If Not (bValue) Then
            value = CType(oValue, String)
        Else
            value = ""
        End If
    Catch ex As Exception
        ' rethrow error ...
        ' Dim Err As New App_Errors("Data_Access_Class", "ExecuteScalar", ex)
        Throw New Exception(ex.InnerException.ToString, ex)
    Finally
        cmd.Connection.Close()
    End Try
    Return value
End Function

Public Function CreateStoredProcCommand(ByVal cmdtext As String) As OracleCommand
    Dim Cmd As New OracleCommand        ' command object ...
    ' create command ...
    With Cmd
        .Connection = Conn
        .CommandText = cmdtext
        .CommandType = CommandType.StoredProcedure
    End With
    Return Cmd
End Function

Вот DDL таблицы.

CREATE TABLE "JOHN"."EMPLOYEE" 
   (    "EMPLOYEE_NUMBER" NUMBER(9,0), 
    "LOCATION_CODE" VARCHAR2(4 BYTE), 
    "SECURITY_LEVEL" NUMBER(2,0), 
    "DATE_LAST_UPDATE" DATE, 
    "DATE_SECURITY_ASSIGNED" DATE, 
    "LAST_PASSWORD_DATE" DATE, 
    "CURRENT_PASSWORD" VARCHAR2(8 BYTE), 
    "FIRST_NAME" VARCHAR2(20 BYTE), 
    "MIDDLE_INITIAL" VARCHAR2(1 BYTE), 
    "LAST_NAME" VARCHAR2(30 BYTE), 
    "USER_ID" VARCHAR2(8 BYTE), 
    "USER_TYPE" CHAR(1 BYTE), 
    "INACTIVE_DATE" DATE, 
    "SECURITY_ASSIGNED_BY" VARCHAR2(8 BYTE), 
    "PASSWORD_EXPIRATION_DATE" DATE, 
    "STATUS_CODE" NUMBER(2,0), 
    "ACCOUNT_LOCKED" VARCHAR2(1 BYTE), 
    "UPDATE_PASS_ON_SIGNON" VARCHAR2(1 BYTE), 
    "USER_EMAIL" VARCHAR2(30 BYTE))

Обратите внимание, что код DDL, хранимые процедуры и VB. Net остались от предыдущего разработчика. Я заменяю реализацию Microsoft драйвера Oracle на ODP. Net. Там нет буквально никаких изменений в коде, кроме этого.

1 Ответ

0 голосов
/ 19 февраля 2020

Храните объекты базы данных локально по отношению к методу, в котором они используются. Таким образом, вы можете контролировать, когда они закрыты и расположены. Соединения и команды могут содержать неуправляемый код, который должен быть освобожден их соответствующими .Dispose методами. В этом примере блок Using...End Using обрабатывает это для вас, даже если есть ошибка.

Я не уверен, почему вы снова создаете хранимую процедуру, когда утверждаете, что она уже находится в Oracle.

Вы можете танцевать с параметрами, создавая массив параметров, затем присваивая значения элементам массива. Метод Parameter.Add автоматически добавляет параметр в коллекцию параметров. Вы используете именованные параметры, но не используете правильные имена. Чтобы избежать этой проблемы, просто используйте позиционные параметры.

Теперь перейдем к фактическому .Execute. .ExecuteScalar возвращает первый столбец первой строки набора результатов. Я не думаю, что вы можете ссылаться на ваш параметр Out в этом сценарии. Без курсора в хранимой процедуре я не уверен, что какой-либо набор результатов будет возвращен.

Попробуйте .ExecuteNonQuery и затем получите значение параметра. Обратите внимание, что мои объекты базы данных закрываются и удаляются с помощью End Using до того, как я начну проверять возвращаемое значение.

Я не могу проверить это, потому что у меня нет установки Oracle, висящей вокруг.

Public Function Get_A_Users_Email(ByVal strEmpId As String) As String
    Dim retVal As Object
    Using cn As New OracleConnection("Your connection string"),
            cmd As New OracleCommand("JOHN.GET_USERS_EMAIL", cn)
        cmd.BindByName = True
        cmd.CommandType = CommandType.StoredProcedure
        cmd.Parameters.Add("User_Email_P", OracleDbType.Varchar2, ParameterDirection.Output)
        cmd.Parameters.Add("Employee_P", OracleDbType.Varchar2, UCase(strEmpId.Trim()), ParameterDirection.Input)
        cn.Open()
        cmd.ExecuteNonQuery()
        retVal = cmd.Parameters("User_Email_P").Value
    End Using
    Dim returnString As String
    If retVal Is Nothing Then
        returnString = ""
    Else
        returnString = retVal.ToString
    End If
    Return returnString
End Function
...