Oracle
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Oracle

Sử dụng GUID của Oracle () - ID được tạo trong Grails / Hibernate

Chà ... sau một ngày vật lộn với điều này, tôi nghĩ rằng tôi đã có thể ôm lấy nó. Câu trả lời này bao quát hơn một chút so với mô tả câu hỏi ban đầu, nhưng đó là bởi vì tôi đã tìm thấy thêm nhiều vấn đề sau khi vượt qua sự cố trình tạo Hibernate.

Sự cố số 1:Lấy GUID() của Oracle giá trị

Như đã được đề cập trong câu trả lời của Adam Hawkes, trình tạo Hibernate "hướng dẫn" là không rõ ràng và chỉ hoạt động cho các phiên bản cũ hơn của phương ngữ Oracle.

Tuy nhiên, nếu bạn sử dụng trình tạo Hibernate "được chỉ định" (nghĩa là bạn muốn đặt các khóa chính theo cách thủ công thay vì để Hibernate tự động tạo chúng), thì bạn có thể chèn các giá trị được lấy từ Oracle SYS_GUID() cuộc gọi.

Mặc dù các phương ngữ Oracle mới hơn của Hibernate không hỗ trợ "hướng dẫn" một cách liền mạch, chúng vẫn hiểu SQL cần thiết để tạo ra các giá trị này. Nếu bạn đang ở bên trong Bộ điều khiển, bạn có thể tìm nạp truy vấn SQL đó bằng cách sau:

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

Thay vào đó, nếu bạn đang ở trong một lớp miền, bạn vẫn có thể thực hiện việc này ... nhưng trước tiên bạn sẽ cần phải đưa một tham chiếu đến grailsApplication. Bạn có thể muốn thực hiện việc này trong Bộ điều khiển, tuy nhiên ... hãy tìm hiểu thêm về điều này bên dưới.

Nếu bạn tò mò, chuỗi thực tế được trả về ở đây (dành cho Oracle) là:

select rawtohex(sys_guid()) from dual

Bạn có thể thực thi SQL này và tìm nạp giá trị ID được tạo như sau:

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

Sự cố số 2:Trên thực tế, việc sử dụng giá trị này trong đối tượng miền Grails

Để thực sự sử dụng giá trị GUID này trong lớp miền Grails của bạn, bạn cần sử dụng trình tạo Hibernate "được chỉ định". Như đã đề cập trước đó, điều này tuyên bố rằng bạn muốn đặt ID của riêng mình theo cách thủ công, thay vì để Grails / GORM / Hibernate tự động tạo chúng. So sánh đoạn mã đã sửa đổi này với đoạn mã trong câu hỏi ban đầu của tôi ở trên:

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

Trong lớp miền của tôi, tôi đã thay đổi "hướng dẫn" thành "được chỉ định". Tôi cũng nhận thấy rằng tôi cần loại bỏ "columns {} "nhóm và di chuyển tất cả thông tin cột của tôi lên một cấp độ (kỳ lạ).

Bây giờ, trong bất kỳ Bộ điều khiển nào đang tạo các đối tượng miền này ... hãy tạo một GUID như được mô tả ở trên và cắm nó vào "id của đối tượng trường ". Trong Bộ điều khiển được tạo tự động bởi Giàn giáo Grails, hàm sẽ là" 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)
}

Bạn có thể nghĩ rằng hãy thử đặt logic này trực tiếp bên trong đối tượng miền, trong một "beforeInsert() "function. Điều đó chắc chắn sẽ gọn gàng và thanh lịch hơn, nhưng có một số lỗi đã biết với Grails khiến ID không được đặt trong" beforeInsert() "đúng cách. Đáng buồn thay, bạn sẽ phải giữ logic này ở cấp Bộ điều khiển.

Sự cố # 3:Đặt Grails / GORM / Hibernate lưu trữ điều này đúng cách

Sự thật rõ ràng là Grails chủ yếu dành cho các ứng dụng hoàn toàn mới và sự hỗ trợ của nó cho các cơ sở dữ liệu kế thừa là khá rõ ràng ( tuy nhiên, công bằng mà nói, nó ít bị lỗi hơn một chút so với các khung "động" khác mà tôi đã thử ). Ngay cả khi bạn sử dụng trình tạo "được chỉ định", đôi khi Grails vẫn bị nhầm lẫn khi nó tiếp tục duy trì đối tượng miền.

Một trong những vấn đề như vậy là ".save() "cuộc gọi đôi khi cố thực hiện CẬP NHẬT khi nó phải thực hiện CHÈN. Lưu ý rằng trong đoạn mã Bộ điều khiển ở trên, tôi đã thêm" insert: true "làm tham số cho" .save() "cuộc gọi. Điều này cho Grails / GORM / Hibernate rõ ràng cố gắng thực hiện thao tác CHÈN chứ không phải là CẬP NHẬT.

Tất cả các ngôi sao và hành tinh phải thẳng hàng để điều này hoạt động bình thường. Nếu lớp miền của bạn "static mapping {} "block không đặt trình tạo Hibernate thành" assigned "và cũng đặt" version false ", thì Grails / GORM / Hibernate sẽ vẫn nhầm lẫn và cố gắng đưa ra CẬP NHẬT thay vì CHÈN.

Nếu bạn đang sử dụng bộ điều khiển Giàn giáo Grails được tạo tự động, thì có thể yên tâm sử dụng "insert: true "trong Bộ điều khiển" save() ", bởi vì hàm đó trong chỉ được gọi khi lưu một đối tượng mới lần đầu tiên. Khi người dùng chỉnh sửa một đối tượng hiện có," update() của Bộ điều khiển "Hàm" được sử dụng thay thế. Tuy nhiên, nếu bạn đang làm việc riêng của mình trong mã tùy chỉnh của riêng bạn ở đâu đó ... thì điều quan trọng là phải kiểm tra xem đối tượng miền đã có trong cơ sở dữ liệu chưa trước khi bạn tạo ".save() "call và chỉ chuyển" insert: true "nếu nó thực sự là lần chèn lần đầu tiên.

Sự cố số 4:Sử dụng các khóa tự nhiên với Grails / GORM / Hibernate

Một lưu ý cuối cùng, không liên quan đến các giá trị GUID của Oracle, nhưng liên quan đến các vấn đề Grails này nói chung. Giả sử rằng trong cơ sở dữ liệu kế thừa (chẳng hạn như cơ sở dữ liệu tôi đã xử lý), một số bảng của bạn sử dụng khóa tự nhiên làm khóa chính của chúng. Giả sử bạn có OWNER_TYPE bảng, chứa tất cả các "loại" có thể có của OWNERNAME vừa là mã định danh con người có thể đọc được vừa là khóa chính.

Bạn sẽ phải làm một số việc khác để làm cho công việc này với Giàn giáo Grails. Thứ nhất, Chế độ xem được tạo tự động không hiển thị trường ID trên màn hình khi người dùng đang tạo đối tượng mới. Bạn sẽ phải chèn một số HTML vào Chế độ xem có liên quan để thêm trường cho ID. Nếu bạn đặt tên cho trường là "id ", thì hàm" save () "của Bộ điều khiển được tạo tự động sẽ nhận giá trị này là" params.id ".

Thứ hai, bạn phải đảm bảo rằng "save() của Bộ điều khiển được tạo tự động "hàm chèn đúng giá trị ID. Khi được tạo lần đầu tiên," save () "bắt đầu bằng cách khởi tạo một đối tượng miền từ các tham số CGI do Chế độ xem truyền vào:

def ownerTypeInstance = new OwnerType.get( params )

Tuy nhiên, điều này không xử lý trường ID bạn đã thêm vào Chế độ xem của mình. Bạn vẫn sẽ cần thiết lập điều đó theo cách thủ công. Nếu trên Chế độ xem, bạn đã đặt tên cho trường HTML là "id ", sau đó nó sẽ có sẵn trong" save() "as" params.id ":

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

Một miếng bánh, hả? Có lẽ "Vấn đề số 5" đang tìm ra lý do tại sao bạn phải vượt qua tất cả nỗi đau này, thay vì chỉ viết giao diện CRUD của bạn bằng tay với Spring Web MVC (hoặc thậm chí là vanilla JSP's) ngay từ đầu! :)



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Làm thế nào để có được số người dựa trên các nhóm tuổi bằng cách sử dụng truy vấn SQL trong cơ sở dữ liệu Oracle?

  2. Dự đoán tăng trưởng bảng Oracle

  3. Addnode Resolutionv.conf Failures

  4. Phép trừ các giá trị dựa trên ID và nhóm sau

  5. Cách nhập liên kết cho một tham số nhiều giá trị trong SQL Developer