Oracle
 sql >> Teknologi Basis Data >  >> RDS >> Oracle

Baca ARRAY dari STRUCT yang dikembalikan oleh prosedur tersimpan

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.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Oracle:Tampilkan nomor baris dengan klausa 'order by'

  2. hibernate hql - kembalikan daftar id baris yang diperbarui setelah menjalankan kueri pembaruan

  3. Tidak Dapat Memasukkan Unicode Menggunakan cx-Oracle

  4. Bagaimana cara mengubah XML ke Objek OCI-Lob?

  5. SSIS dan mengirim kueri dengan tanggal ke Oracle