Tạo các đối tượng triển khai java.sql.SQLData
. Trong trường hợp này, hãy tạo TEnclosure
và TAnimal
các lớp, cả hai đều triển khai SQLData
.
Chỉ FYI, trong các phiên bản Oracle JDBC mới hơn, các loại như oracle .sql.ARRAY
không được dùng nữa để ủng hộ java.sql
các loại. Mặc dù tôi không chắc cách viết một mảng (được mô tả dưới đây) chỉ bằng cách sử dụng java.sql
API.
Khi bạn triển khai readSQL()
bạn đọc các trường theo thứ tự. Bạn nhận được java.sql.Array
với sqlInput.readArray()
. Vì vậy, TEnclosure.readSQL()
sẽ trông giống như thế này.
@Override
public void readSQL(SQLInput sqlInput, String s) throws SQLException {
id = sqlInput.readBigDecimal();
name = sqlInput.readString();
Array animals = sqlInput.readArray();
// what to do here...
}
Lưu ý:readInt()
cũng tồn tại, nhưng Oracle JDBC dường như luôn cung cấp BigDecimal
cho NUMBER
Bạn sẽ nhận thấy rằng một số API như java.sql.Array
có các phương thức lấy một loại bản đồ Map<String, Class<?>>
Đây là ánh xạ các tên kiểu Oracle tới lớp Java tương ứng của chúng khi triển khai SQLData
(ORAData
cũng có thể hoạt động?).
Nếu bạn chỉ gọi Array.getArray()
, bạn sẽ nhận được Struct
các đối tượng trừ khi trình điều khiển JDBC biết về các ánh xạ kiểu của bạn thông qua Connection.setTypeMap(typeMap)
. Tuy nhiên, việc đặt typeMap trên kết nối không hoạt động với tôi, vì vậy tôi sử dụng getArray(typeMap)
Tạo Map<String, Class<?>> typeMap
của bạn ở đâu đó và thêm các mục nhập cho các loại của bạn:
typeMap.put("T_ENCLOSURE", TEnclosure.class);
typeMap.put("T_ANIMAL", TAnimal.class);
Trong một SQLData.readSQL()
triển khai, gọi sqlInput.readArray().getArray(typeMap)
, trả về Object[]
nơi Object
các mục nhập hoặc thuộc loại TAnimal
.
Tất nhiên là mã để chuyển đổi thành List<TAnimal>
tẻ nhạt, vì vậy chỉ cần sử dụng chức năng tiện ích này và điều chỉnh nó theo nhu cầu của bạn theo chính sách danh sách rỗng và trống:
/**
* Constructs a list from the given SQL Array
* Note: this needs to be static because it's called from SQLData classes.
*
* @param <T> SQLData implementing class
* @param array Array containing objects of type T
* @param typeClass Class reference used to cast T type
* @return List<T> (empty if array=null)
* @throws SQLException
*/
public static <T> List<T> listFromArray(Array array, Class<T> typeClass) throws SQLException {
if (array == null) {
return Collections.emptyList();
}
// Java does not allow casting Object[] to T[]
final Object[] objectArray = (Object[]) array.getArray(getTypeMap());
List<T> list = new ArrayList<>(objectArray.length);
for (Object o : objectArray) {
list.add(typeClass.cast(o));
}
return list;
}
Mảng viết
Việc tìm ra cách viết một mảng thật khó chịu, các API Oracle yêu cầu một Kết nối để tạo một Mảng, nhưng bạn không có một Kết nối rõ ràng trong ngữ cảnh của writeSQL(SQLOutput sqlOutput)
. May mắn thay, blog này
có một thủ thuật / hack để lấy OracleConnection
, mà tôi đã sử dụng ở đây.
Khi bạn tạo một mảng với createOracleArray()
bạn chỉ định loại danh sách (T_ARRAY_ANIMALS
) cho tên kiểu, KHÔNG PHẢI là kiểu đối tượng số ít.
Đây là một hàm chung để viết mảng. Trong trường hợp của bạn, listType
sẽ là "T_ARRAY_ANIMALS"
và bạn sẽ chuyển vào List<TAnimal>
/**
* Write the list out as an Array
*
* @param sqlOutput SQLOutput to write array to
* @param listType array type name (table of type)
* @param list List of objects to write as an array
* @param <T> Class implementing SQLData that corresponds to the type listType is a list of.
* @throws SQLException
* @throws ClassCastException if SQLOutput is not an OracleSQLOutput
*/
public static <T> void writeArrayFromList(SQLOutput sqlOutput, String listType, @Nullable List<T> list) throws SQLException {
final OracleSQLOutput out = (OracleSQLOutput) sqlOutput;
OracleConnection conn = (OracleConnection) out.getSTRUCT().getJavaSqlConnection();
conn.setTypeMap(getTypeMap()); // not needed?
if (list == null) {
list = Collections.emptyList();
}
final Array array = conn.createOracleArray(listType, list.toArray());
out.writeArray(array);
}
Ghi chú:
- Có lúc tôi nghĩ
setTypeMap
là bắt buộc, nhưng bây giờ khi tôi xóa dòng đó, mã của tôi vẫn hoạt động, vì vậy tôi không chắc liệu nó có cần thiết hay không. - Tôi không chắc bạn nên viết null hay mảng trống, nhưng tôi cho rằng mảng trống thì đúng hơn.
Mẹo về các loại Oracle
- Oracle viết hoa mọi thứ, vì vậy tất cả các tên loại phải là chữ hoa.
- Bạn có thể cần chỉ định
SCHEMA.TYPE_NAME
nếu loại không có trong giản đồ mặc định của bạn. - Nhớ
grant execute
trên các loại nếu người dùng bạn đang kết nối không phải là chủ sở hữu.
Nếu bạn thực thi trên gói nhưng không phải loại,getArray()
sẽ đưa ra một ngoại lệ khi nó cố gắng tìm kiếm siêu dữ liệu loại.
Mùa xuân
Dành cho các nhà phát triển sử dụng Spring , bạn có thể muốn xem Spring Data JDBC Extensions
, cung cấp SqlArrayValue
và SqlReturnArray
, rất hữu ích để tạo SimpleJdbcCall
cho một thủ tục nhận một mảng làm đối số hoặc trả về một mảng.
Chương 7.2.1 Đặt giá trị ARRAY bằng SqlArrayValue cho tham số IN giải thích cách gọi các thủ tục với các tham số mảng.