Чтобы использовать Spring для вызова хранимой процедуры Oracle, которая принимает параметр, тип которого является таблицей объекта, необходимо выполнить несколько действий.
Во-первых, вам нужно создайте класс Java, который соответствует Oracle типу объекта T_OBJECT_FROM_EXCEL
. Необходимо реализовать интерфейс SQLData . Это будет выглядеть примерно так (пожалуйста, не стесняйтесь изменять имена полей соответствующим образом):
import java.sql.SQLData;
import java.sql.SQLException;
import java.sql.SQLInput;
import java.sql.SQLOutput;
public class ExcelRow implements SQLData {
private String objectGroup;
private String objectCode;
private String prodMatrixId;
private String prodChannelId;
private String prodSalesGroupId;
private String prodCustGroup;
private String slsThroughId;
private boolean active;
// ... constructor, getters and setters omitted ...
@Override
public String getSQLTypeName() {
return "PARAMS.T_OBJECT_FROM_EXCEL";
}
@Override
public void readSQL(SQLInput sqlInput, String typeName) throws SQLException {
throw new SQLException("This has not been implemented");
}
@Override
public void writeSQL(SQLOutput sqlOutput) throws SQLException {
sqlOutput.writeString(this.objectGroup);
sqlOutput.writeString(this.objectCode);
sqlOutput.writeString(this.prodMatrixId);
sqlOutput.writeString(this.prodChannelId);
sqlOutput.writeString(this.prodSalesGroupId);
sqlOutput.writeString(this.prodCustGroup);
sqlOutput.writeString(this.slsThroughId);
sqlOutput.writeInt(this.active ? 1 : 0);
}
}
Интерфейс SQLData имеет три метода: getSQLTypeName()
, readSQL()
и writeSQL()
. getSQLTypeName()
возвращает имя типа Oracle, которому мы сопоставляем, а writeSQL()
записывает данные в объекте ExcelRow
в данный выходной объект sqlOutput
. Порядок полей, которые мы пишем, должен соответствовать порядку, в котором они объявлены в T_OBJECT_FROM_EXCEL
. readSQL()
используется для преобразования объекта T_OBJECT_FROM_EXCEL
, возвращенного из базы данных, в ExcelRow
, но мы заинтересованы только в отправке значений в базу данных, а не в получении их из базы данных, поэтому для краткости я только что реализовал это вызывает исключение.
Во-вторых, вам нужно настроить код, который вызывает хранимую процедуру. Ваш метод executeSPForInsertData
выглядит несколько обобщенно c в том смысле, что он использует хранимую процедуру и произвольную карту параметров. Из-за параметра табличного типа эту хранимую процедуру немного неудобно вызывать обобщенным образом c, поэтому мы напишем метод, предназначенный специально для этого вызова хранимой процедуры:
public void executeSPForInsertData(DataSource ds, ExcelRow[] excelRows){
String parameterName = "P_T_TABLE_UPLD_EXCEL";
SqlParameter[] parameterTypes = { new SqlParameter(parameterName, OracleTypes.ARRAY, "PARAMS.EXCEL") };
Map<String, Object> parameters =
Collections.singletonMap(parameterName, new SqlArrayValue<>(excelRows));
SimpleJdbcCall jdbcCall = new SimpleJdbcCall(ds)
.withSchemaName("PARAMS")
.withCatalogName("PKG_PARA_UPLD_VAL")
.withProcedureName("PR_SP_FAHMI")
.withoutProcedureColumnMetaDataAccess()
.declareParameters(parameterTypes);
jdbcCall.execute(parameters);
}
Мы начнем с объявления типов параметров: есть один параметр и это массив, чей тип Oracle равен EXCEL
в схеме PARAMS
. Затем мы объявляем значения параметров, используя SqlArrayValue
для переноса массива ExcelRow
s, которые мы передаем. Наконец, мы устанавливаем вызов хранимой процедуры и затем вызываем его. Поскольку имя параметра используется дважды, я поместил его в локальную переменную.
Я дал это быстрое тестирование с базой данных Oracle 18 c XE, и это сработало, так как я мог назвать это хранимым процедуры и пусть он записывает данные в базу данных.