Buat objek yang mengimplementasikan java.sql.SQLData
. Dalam skenario ini, buat TEnclosure
dan TAnimal
kelas, yang keduanya mengimplementasikan SQLData
.
Sekadar informasi, dalam versi Oracle JDBC yang lebih baru, ketik seperti oracle .sql.ARRAY
tidak digunakan lagi karena java.sql
jenis. Meskipun saya tidak yakin bagaimana menulis sebuah array (dijelaskan di bawah) hanya menggunakan java.sql
API.
Saat Anda mengimplementasikan readSQL()
Anda membaca bidang secara berurutan. Anda mendapatkan java.sql.Array
dengan sqlInput.readArray()
. Jadi TEnclosure.readSQL()
akan terlihat seperti ini.
@Override
public void readSQL(SQLInput sqlInput, String s) throws SQLException {
id = sqlInput.readBigDecimal();
name = sqlInput.readString();
Array animals = sqlInput.readArray();
// what to do here...
}
Catatan:readInt()
juga ada, tetapi Oracle JDBC tampaknya selalu menyediakan BigDecimal
untuk NUMBER
Anda akan melihat bahwa beberapa API seperti java.sql.Array
memiliki metode yang mengambil jenis peta Map<String, Class<?>>
Ini adalah pemetaan nama tipe Oracle ke kelas Java terkait yang mengimplementasikan SQLData
(ORAData
bisa bekerja juga?).
Jika Anda hanya memanggil Array.getArray()
, Anda akan mendapatkan Struct
objek kecuali driver JDBC mengetahui tentang pemetaan tipe Anda melalui Connection.setTypeMap(typeMap)
. Namun, pengaturan typeMap pada koneksi tidak berfungsi untuk saya, jadi saya menggunakan getArray(typeMap)
Buat Map<String, Class<?>> typeMap
. Anda di suatu tempat dan tambahkan entri untuk tipe Anda:
typeMap.put("T_ENCLOSURE", TEnclosure.class);
typeMap.put("T_ANIMAL", TAnimal.class);
Dalam SQLData.readSQL()
implementasi, panggil sqlInput.readArray().getArray(typeMap)
, yang mengembalikan Object[]
dimana Object
entri atau dari jenis TAnimal
.
Tentu saja kode untuk dikonversi ke List<TAnimal>
menjadi membosankan, jadi gunakan saja fungsi utilitas ini dan sesuaikan dengan kebutuhan Anda sejauh kebijakan daftar nol vs kosong:
/**
* 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;
}
Menulis Array
Mencari tahu cara menulis array membuat frustrasi, Oracle API memerlukan Koneksi untuk membuat Array, tetapi Anda tidak memiliki Koneksi yang jelas dalam konteks writeSQL(SQLOutput sqlOutput)
. Untungnya, blog ini
memiliki trik/retas untuk mendapatkan OracleConnection
, yang telah saya gunakan di sini.
Saat Anda membuat array dengan createOracleArray()
Anda menentukan jenis daftar (T_ARRAY_ANIMALS
) untuk nama tipe, BUKAN tipe objek tunggal.
Berikut adalah fungsi umum untuk menulis array. Dalam kasus Anda, listType
akan menjadi "T_ARRAY_ANIMALS"
dan Anda akan memasukkan 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);
}
Catatan:
- Pada satu titik saya pikir
setTypeMap
diperlukan, tetapi sekarang ketika saya menghapus baris itu, kode saya masih berfungsi, jadi saya tidak yakin apakah itu perlu. - Saya tidak yakin apakah Anda harus menulis null atau array kosong, tetapi saya berasumsi bahwa array kosong lebih benar.
Kiat tentang tipe Oracle
- Oracle huruf besar semuanya, jadi semua nama jenis harus huruf besar.
- Anda mungkin perlu menentukan
SCHEMA.TYPE_NAME
jika jenisnya tidak ada dalam skema default Anda. - Ingatlah untuk
grant execute
pada tipe jika pengguna yang Anda hubungkan bukan pemiliknya.
Jika Anda telah mengeksekusi paket, tetapi bukan tipenya,getArray()
akan mengeluarkan pengecualian ketika mencoba mencari jenis metadata.
Musim semi
Untuk pengembang yang menggunakan Musim Semi , Anda mungkin ingin melihat Ekstensi JDBC Data Musim Semi
, yang menyediakan SqlArrayValue
dan SqlReturnArray
, yang berguna untuk membuat SimpleJdbcCall
untuk prosedur yang menggunakan larik sebagai argumen atau mengembalikan larik.
Bab 7.2.1 Menyetel nilai ARRAY menggunakan SqlArrayValue untuk parameter IN menjelaskan cara memanggil prosedur dengan parameter larik.