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

Menggunakan Oracle's GUID()-generated ID di Grails/Hibernate

Wah... setelah seharian bergulat dengan ini, saya pikir saya memiliki tangan saya di sekitar hal itu. Jawaban ini mencakup sedikit lebih banyak dasar daripada deskripsi pertanyaan awal, tetapi itu karena saya menemukan lebih banyak masalah setelah mengatasi masalah generator Hibernate.

Masalah #1:Mendapatkan Oracle GUID() nilai

Seperti yang dicakup oleh jawaban Adam Hawkes, generator Hibernate "panduan" tidak dirawat dan hanya berfungsi untuk versi dialek Oracle yang lebih lama.

Namun, jika Anda menggunakan generator Hibernate "ditugaskan" (artinya Anda ingin mengatur kunci utama secara manual daripada membuat Hibernate otomatis), maka Anda dapat memasukkan nilai yang ditarik dari Oracle SYS_GUID() telepon.

Meskipun dialek Oracle Hibernate yang lebih baru tidak mendukung "panduan" dengan mulus, mereka masih memahami SQL yang diperlukan untuk menghasilkan nilai-nilai ini. Jika Anda berada di dalam Controller, Anda dapat mengambil kueri SQL tersebut dengan perintah berikut:

String guidSQL = grailsApplication.getMainContext().sessionFactory.getDialect().getSelectGUIDString()

Jika Anda berada di dalam kelas domain, Anda masih dapat melakukan ini... tetapi Anda harus terlebih dahulu menyuntikkan referensi ke grailsApplication. Anda mungkin ingin melakukan ini di Controller... lebih lanjut tentang ini di bawah.

Jika Anda penasaran, String sebenarnya yang dikembalikan di sini (untuk Oracle) adalah:

select rawtohex(sys_guid()) from dual

Anda dapat menjalankan SQL ini dan mengambil nilai ID yang dihasilkan seperti ini:

String guid = grailsApplication.getMainContext().sessionFactory.currentSession.createSQLQuery(guidSQL).list().get(0)

Masalah #2:Sebenarnya menggunakan nilai ini dalam objek domain Grails

Untuk benar-benar menggunakan nilai GUID ini di kelas domain Grails Anda, Anda perlu menggunakan generator Hibernate "ditugaskan". Seperti disebutkan sebelumnya, ini menyatakan bahwa Anda ingin mengatur ID Anda sendiri secara manual, daripada membiarkan Grails/GORM/Hibernate menghasilkannya secara otomatis. Bandingkan cuplikan kode yang dimodifikasi ini dengan yang ada di pertanyaan awal saya di atas:

...
static mapping = {
    table name: "OWNER"
    version false
    id column: "OWNER_OID", generator: "assigned"
    name column: "NAME"
    ...
}
...

Di kelas domain saya, saya mengubah "panduan" menjadi "ditugaskan". Saya juga menemukan bahwa saya perlu menghilangkan "columns {} " blok pengelompokan, dan pindahkan semua informasi kolom saya ke atas (aneh).

Sekarang, di mana pun Pengendali membuat objek domain ini... buat GUID seperti yang dijelaskan di atas, dan hubungkan ke "id objek" ". Dalam Controller yang dibuat secara otomatis oleh Grails Scaffolding, fungsinya adalah "save() ":

def save() {
    def ownerInstance = new Owner(params)
    String guidSQL = grailsApplication.getMainContext().sessionFactory.getDialect().getSelectGUIDString()
    ownerInstance.id = grailsApplication.getMainContext().sessionFactory.currentSession.createSQLQuery(guidSQL).list().get(0)

    if (!ownerInstance.save(flush: true, insert: true)) {
        render(view: "create", model: [ownerInstance: ownerInstance])
        return
    }

    flash.message = message(code: 'default.created.message', args: [message(code: 'owner.label', default: 'Owner'), ownerInstance.id])
    redirect(action: "show", id: ownerInstance.id)
}

Anda mungkin berpikir untuk mencoba menempatkan logika ini langsung di dalam objek domain, di "beforeInsert() " fungsi. Itu pasti akan lebih bersih dan lebih elegan, tetapi ada beberapa bug yang diketahui dengan Grails yang mencegah ID diatur di "beforeInsert() " dengan benar. Sayangnya, Anda harus menjaga logika ini di level Pengendali.

Masalah #3:Jadikan Grails/GORM/Hibernate menyimpan ini dengan benar

Kebenaran yang jelas adalah bahwa Grails terutama ditujukan untuk aplikasi baru, dan dukungannya untuk basis data lama cukup buruk (secara adil, ini sedikit kurang jerawatan daripada kerangka kerja "dinamis" lain yang pernah saya coba ). Bahkan jika Anda menggunakan generator yang "ditugaskan", Grails terkadang menjadi bingung ketika harus mempertahankan objek domain.

Salah satu masalah tersebut adalah bahwa ".save() " panggilan terkadang mencoba melakukan UPDATE padahal seharusnya melakukan INSERT. Perhatikan bahwa dalam cuplikan Controller di atas, saya telah menambahkan "insert: true " sebagai parameter ke ".save() " panggilan. Ini memberitahu Grails/GORM/Hibernate secara eksplisit untuk mencoba operasi INSERT daripada operasi UPDATE.

Semua bintang dan planet harus sejajar agar ini berfungsi dengan baik. Jika kelas domain Anda "static mapping {} " blok tidak menyetel generator Hibernate ke "assigned ", dan juga atur "version false ", maka Grails/GORM/Hibernate masih akan bingung dan mencoba mengeluarkan UPDATE daripada INSERT.

Jika Anda menggunakan pengontrol Grails Scaffolding yang dibuat secara otomatis, maka aman untuk menggunakan "insert: true " di "save() Pengontrol" ", karena fungsi tersebut hanya dipanggil saat menyimpan objek baru untuk pertama kalinya. Saat pengguna mengedit objek yang sudah ada, "update() Controller " digunakan sebagai gantinya. Namun, jika Anda melakukan hal Anda sendiri dalam kode kustom Anda sendiri di suatu tempat... penting untuk memeriksa apakah objek domain sudah ada di database sebelum Anda membuat ".save() " panggil, dan hanya berikan "insert: true " parameter jika itu benar-benar penyisipan pertama kali.

Masalah #4:Menggunakan kunci alami dengan Grails/GORM/Hibernate

Satu catatan terakhir, tidak ada hubungannya dengan nilai Oracle GUID, tetapi terkait dengan masalah Grails ini secara umum. Katakanlah dalam database lama (seperti yang pernah saya tangani), beberapa tabel Anda menggunakan kunci alami sebagai kunci utamanya. Katakanlah Anda memiliki OWNER_TYPE tabel, yang berisi semua "jenis" yang mungkin dari OWNER , dan NAME kolom adalah pengidentifikasi yang dapat dibaca manusia dan juga kunci utama.

Anda harus melakukan beberapa hal lain untuk membuatnya bekerja dengan Grails Scaffolding. Untuk satu hal, Tampilan yang dibuat secara otomatis tidak menampilkan bidang ID di layar saat pengguna membuat objek baru. Anda harus memasukkan beberapa HTML ke Tampilan yang relevan untuk menambahkan bidang untuk ID. Jika Anda memberi nama bidang "id ", maka fungsi "save()" Pengontrol yang dibuat secara otomatis akan menerima nilai ini sebagai "params.id ".

Kedua, Anda harus memastikan bahwa "save() . Pengontrol yang dibuat secara otomatis " berfungsi dengan benar memasukkan nilai ID. Saat pertama kali dibuat, "save()" dimulai dengan membuat instance objek domain dari parameter CGI yang diteruskan oleh View:

def ownerTypeInstance = new OwnerType.get( params )

Namun, ini tidak menangani bidang ID yang Anda tambahkan ke Tampilan Anda. Anda masih perlu mengaturnya secara manual. Jika pada Tampilan Anda memberi bidang HTML nama "id ", maka akan tersedia di "save() " sebagai "params.id ":

...
ownerTypeInstance = new OwnerType()
ownerTypeInstance.id = params.id 
// Proceed to the ".save()" step, making sure to pass "insert: true"
...

Sepotong kue, ya? Mungkin "Masalah #5" adalah mencari tahu mengapa Anda menempatkan diri Anda melalui semua rasa sakit ini, daripada hanya menulis antarmuka CRUD Anda dengan tangan dengan Spring Web MVC (atau bahkan vanilla JSP) di tempat pertama! :)



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Sql Pesan dengan di beberapa kolom

  2. Kembalikan nilai oci_parse

  3. Bagaimana cara mengatasi ORA-29471 di dbms_sql.open_cursor?

  4. Sesi alter memperlambat kueri melalui Hibernate

  5. ORA-06553:PLS-801:kesalahan internal [55018] saat menguji fungsi mengembalikan ROWTYPE