Oracle Entity Framework Core передает параметр таблицы в хранимую процедуру - PullRequest
0 голосов
/ 08 ноября 2019

Я пытаюсь передать параметр в хранимую процедуру, используя пакет Oracle.EntityFrameworkCore, например:

DataTable table = new DataTable();
table.Columns.Add("keyColumn", typeof(string));
table.Columns.Add("valueColumn", typeof(string));

var row = table.NewRow();
row.ItemArray = new object[]
{
    entry.KeyColumn,
    entry.ValueColumn
};

table.Rows.Add(row);

var parameter = new OracleParameter("entries",table);
parameter.UdtTypeName = "entry_type_list";


return context.Database.ExecuteSqlCommandAsync(
    new RawSqlString( @"EXEC set_entry_list (:entries)" ),
    parameter);

Хранимая процедура и тип определяются следующим образом:

CREATE OR REPLACE TYPE entry_type AS OBJECT
(
"keyColumn" NVARCHAR2(3), 
"valueColumn" NVARCHAR2(3)
);

CREATE OR REPLACE TYPE entry_type_list AS TABLE OF entry_type;

CREATE OR REPLACE PROCEDURE set_entry_list (entries entry_type_list) AS
BEGIN
REM Doing stuff
END;

Но я получаю сообщение об ошибке:

System.ArgumentException: значение не попадает в ожидаемый диапазон.
в Oracle.ManagedDataAccess.Client.OracleParameter..ctor (String параметрName, Object obj)

Единственным источником для этого является ответ как это сделать с SQL Server, но нет ответа для Oracle с EFCore. Проблема здесь заключается в том, что Oracle принимает OracleParameter, тогда как другие используют SqlParameter.

Если я использую тип SqlParameter следующим образом:

var parameter = new SqlParameter("entries", SqlDbType.Structured);
parameter.TypeName = "entry_type_list";
parameter.Value = table;

Я получаю эту ошибку:

System.InvalidCastException: Невозможно привести объект типа'System.Data.SqlClient.SqlParameter' для ввода 'Oracle.ManagedDataAccess.Client.OracleParameter'.

Я также пытался установить parameter.OracleDbType для различных значений, таких как Blob, RefCursor,Clob или XmlType, установка parameter.DbType на Object или установка CollectionType на PLSQLAssociativeArray безуспешно. Кроме того, передача таблицы или массива объектов вместо таблицы не удалась.

В настоящее время я понятия не имею, что еще можно попробовать.

Любой метод для передачи большого количества объектов вхранимая процедура в быстром виде поможет. Я использую их с командой слияния, поэтому мне нужно иметь возможность преобразовать эти параметры в таблицу.

1 Ответ

0 голосов
/ 12 ноября 2019

Теперь я нашел решение, используя временную таблицу и используя эту в качестве входного параметра.

Поскольку я не могу передать полную таблицу, но массив простых объектов, я должен заполнить эту таблицупередавая один массив для каждого столбца:

var keyColumn = new OracleParameter( "keyColumn", OracleDbType.Decimal );
keyColumn.Value = values.Select( c => c.KeyColumn).ToArray();
var valueColumn = new OracleParameter( "valueColumn", OracleDbType.Decimal );
valueColumn = values.Select( c => c.ValueColumn).ToArray();

using ( var transaction = this.dbContext.Database.BeginTransaction( IsolationLevel.ReadCommitted) )
{
    var connection = this.dbContext.Database.GetDbConnection() as OracleConnection;
    OracleCommand cmd = connection.CreateCommand();

    cmd.CommandText = @"
        INSERT INTO TMP_TABLE 
        (
        ""keyColumn"",
        ""valueColumn""
        )
        VALUES (
        :keyColumn,
        :valueColumn)";
    cmd.Parameters.Add( keyColumn ); 
    cmd.Parameters.Add( valueColumn );
    cmd.ArrayBindCount = values.Length;
    var insertCount = await cmd.ExecuteNonQueryAsync();


    cmd = connection.CreateCommand();
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.CommandText = "dbo.stored_procedure";

    var result = await cmd.ExecuteNonQueryAsync();
    transaction.Commit();
}

Я создал временную таблицу следующим образом:

CREATE
GLOBAL TEMPORARY TABLE "dbo"."TMP_TABLE"
ON COMMIT DELETE ROWS
 AS SELECT * FROM "dbo"."REAL_TABLE" WHERE 0=1;

И изменил свою хранимую процедуру, чтобы использовать ее:

CREATE OR REPLACE PROCEDURE stored_procedure AS 
BEGIN
    REM use the "dbo"."TMP_TABLE"
END;

Этот ответ помог мне с подходом массовой вставки с одним массивом на столбец. В этой ветке также содержится дальнейшее обсуждение темы и более общий подход.

...