2012-12-05 36 views
5

Trong vũ trụ điên rồ của tôi, Phòng có thể có nhiều ghế và ghế có thể 'thuộc' cho nhiều phòng. Trong grails nó trông như thế này. Ghế không nên biết phòng thuộc về họ.Bắt 'vi phạm ràng buộc toàn vẹn tham chiếu' khi xóa đối tượng miền

class Room { 
    String name 
    static hasMany = [chairs: Chair] 
    static constraints = { 
    } 
} 
class Chair { 
    String name 
    static constraints = { 
    } 
} 

Tôi muốn xóa ghế và tự động xóa mọi tham chiếu ghế trong tất cả các đối tượng miền phòng có ghế đó. Tôi đã thành công, nhưng với một sửa chữa mà tôi không thích. Trong ChairController tôi đã làm như sau

def deleleChair(){ 
    def chairToDelete = Chair.get(params.id) 
    Room.findAll().each {room-> 
     if(room.chairs.contains(chairToDelete)){ 
      room.removeFromChairs(chairToDelete) 
      room.save(failOnError:true) 
     } 
    } 
    chairToDelete.delete(params.chairId) 
} 

Có cấu hình hibernate mà tôi cần thiết để tự động thực hiện điều này không? Nó có vẻ như một cái gì đó rất phổ biến trong các tình huống thế giới thực. Tôi sẽ không muốn thực hiện cùng một đoạn mã, khi tôi có thể quyết định, (ví dụ điên rồ) rằng một đối tượng miền xe có thể có nhiều ghế.

Tôi đã cố sử dụng plugin đẩy sự kiện grails. Tôi đã có một ChairService với một hành động lắng nghe các sự kiện beforeDelete trong gorm.

class ChairService { 
    @grails.events.Listener(topic = 'beforeDelete', namespace = "gorm") 
    def handleDeletedChair(Chair chair){ 
     Room.findAll().each {room-> 
      if(room.chairs.contains(chairToDelete)){ 
       room.removeFromChairs(chairToDelete) 
       room.save(failOnError:true, flush:true) 
      } 
     } 
    } 
} 

Chức năng này được gọi là bất cứ khi nào một chiếc ghế xóa được cố gắng, nhưng khi nó trở về ChairController để làm việc xóa ghế thực tế, hành động xóa vẫn nghĩ rằng các tài liệu tham khảo để phòng vẫn còn đó và ném một

Caused by JdbcSQLException: Referential integrity constraint violation:"FK4ACA6A6151428364: PUBLIC.ROOM_CHAIR FOREIGN KEY(CHAIR_ID) REFERENCES PUBLIC.CHAIR(ID)"; SQL statement: 

xóa khỏi ghế có id =? và phiên bản =? [23503-164]

Tôi muốn logic này tách biệt khỏi ghế, ghế không bao giờ nên không có phòng.

+1

Nếu bạn không quan tâm rằng Chủ tịch có thể xem Phòng, điều này dễ dàng hơn rất nhiều. – Gregg

Trả lời

1

Một giải pháp đơn giản là sử dụng SQL tiêu chuẩn:

import grails.events.Listener 
import groovy.sql.Sql 

class ChairService { 
    def dataSource // autowired 

    @Listener(topic='beforeDelete', namespace='gorm') 
     def handleDeletedChair(Chair chairToDelete) { 
     new Sql(dataSource).execute('DELETE FROM room_chair WHERE chair_id=?', [chairToDelete.id]) 
     return true 
    } 
} 

Vì đây là SQL nó có thể phụ thuộc vào cơ sở dữ liệu bạn đang sử dụng (tôi thử nghiệm với H2).

+0

Tôi đã thử điều này và nó hoạt động hoàn hảo – user1879106

1

Vì mối quan hệ không tồn tại hai chiều Tôi không chắc chắn có một giải pháp thanh lịch hơn nhiều.

Tuy nhiên, nếu bạn đang làm việc với rất nhiều phòng/ghế, tôi khuyên bạn nên sử dụng truy vấn tiêu chí với dự đoán chỉ tải lên các id bạn muốn xóa thay vì tải tất cả các phòng lên ghế. Tốt hơn là sử dụng phương pháp executeUpdate để xóa 'hàng loạt'. Làm như vậy cũng sẽ giúp bạn khắc phục lỗi.

grails criteria query docs...

deleting objects in grails docs...

0

Tôi bắt gặp các lỗi trong ChairController.delete và đây là lỗi mà được ném. Việc xóa diễn ra và sự liên kết bị loại bỏ nhưng sự giải thích được ném ra. Giải pháp của tôi khá khó chịu, về cơ bản tôi đã bị loại trừ và hiển thị chế độ xem có liên quan sau đó.

Caused by HibernateOptimisticLockingFailureException: Object of class [test.cascade.Chair] with identifier [2]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [test.cascade.Chair#2] 
->> 10 | doCall    in test.cascade.ChairService$_handleDeletedChair_closure1 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|  7 | handleDeletedChair in test.cascade.ChairService 
| 238 | invoke . . . . . . in org.grails.plugin.platform.events.registry.DefaultEventsRegistry$ListenerHandler 
| 159 | invokeListeners in org.grails.plugin.platform.events.registry.DefaultEventsRegistry 
|  69 | event . . . . . . in org.grails.plugin.platform.events.publisher.DefaultEventsPublisher 
| 149 | event    in org.grails.plugin.platform.events.EventsImpl 
|  70 | onApplicationEvent in org.grails.plugin.platform.events.publisher.GormBridgePublisher 
| 1110 | runWorker   in java.util.concurrent.ThreadPoolExecutor 
| 603 | run . . . . . . . in java.util.concurrent.ThreadPoolExecutor$Worker 
^ 722 | run    in java.lang.Thread 

Caused by StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [test.cascade.Chair#2] 
->> 10 | doCall    in test.cascade.ChairService$_handleDeletedChair_closure1 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|  7 | handleDeletedChair in test.cascade.ChairService 
| 238 | invoke . . . . . . in org.grails.plugin.platform.events.registry.DefaultEventsRegistry$ListenerHandler 
| 159 | invokeListeners in org.grails.plugin.platform.events.registry.DefaultEventsRegistry 
|  69 | event . . . . . . in org.grails.plugin.platform.events.publisher.DefaultEventsPublisher 
| 149 | event    in org.grails.plugin.platform.events.EventsImpl 
|  70 | onApplicationEvent in org.grails.plugin.platform.events.publisher.GormBridgePublisher 
| 1110 | runWorker   in java.util.concurrent.ThreadPoolExecutor 
| 603 | run . . . . . . . in java.util.concurrent.ThreadPoolExecutor$Worker 
^ 722 | run    in java.lang.Thread 
Các vấn đề liên quan