2012-10-03 70 views
0

我有一個適度複雜的設計,我試圖從系統中刪除一個「ItemCollection」。此對象屬於發佈者(一對多),並具有MediaItems(一對多)和一個發佈(一對一)。發佈是由非擁有多對多的其他2個對象引用的。刪除域對象和外鍵

當我刪除I​​temCollection(通過調用父級上的removeFrom())時,會觸發級聯,但是我在多對多集合上結束了外鍵異常。我嘗試從beforeDelete()中的其他集合中刪除Posting,雖然我的日誌記錄輸出告訴我這是正常工作,但仍然會出現外鍵異常。

主要層次是在這裏:

class Publisher { 
    String name 
    static hasMany = [collections : ItemCollection, defaultTags : MetaTag, feeds : Feed] 

    static mapping = { 
     collections cascade: 'all-delete-orphan' 
    } 
} 

class ItemCollection { 

    static hasOne = [posting:Posting] 
    static hasMany = [items:MediaItem, tags:MetaTag] 
    static mapping = { 
     items sort:'collectionOrder', order: 'asc', lazy:false, cascade: "all-delete-orphan" 
     posting cascade: "all-delete-orphan" 
     tags lazy:false 
    } 
    static belongsTo = [publisher:Publisher] 
} 


class Posting { 
    static belongsTo = [itemCollection: ItemCollection] 

    << see beforeDelete method below >> 
} 

發佈由這兩個類引用。

class ItemFeed { 
    List posts 
    static hasMany = [posts:Posting, segments:FeedSegment] 

    static mapping = { 
     segments cascade: 'all-delete-orphan' 
     posts lazy:'false' 

    } 
    static constraints = { 
     posts nullable:true 
     segments nullable:true 
    } 
} 

class FeedSegment { 
    Date postingTime 
    String s3objname 
    List posts 

    static belongsTo = [feed:ItemFeed] 
    static hasMany = [posts:Posting] 

    static constraints = { 
     posts nullable:true 
    } 
} 

在我的控制器我打電話:

collectionIds.addAll(params?.collectionIds) 
collectionIds.each { id-> 
    log.info("deleting ${id}") 
    def itemCollectionInstance = ItemCollection.get(id) 
    def publisher = itemCollectionInstance.publisher 
    publisher.removeFromCollections(itemCollectionInstance) 
    publisher.save(flush:true) 
} 

而且我已經添加了以下onDelete張貼。

def beforeDelete() { 
     Posting.withNewSession { 
      log.info 'trying to delete posting from feeds' 

      Posting thees = Posting.get(id) /// using "this" seemed to not be reliable..? 
      log.info 'Deleting: ' + thees 

      def feedsWithPost = ItemFeed.createCriteria().list{ 
       posts { 
        eq('id', thees.id) 
       } 
      } 

      def x = feedsWithPost 
      x.each { feed -> 
       log.info '#posts: ' + feed.posts.size() 
       feed.removeFromPosts(thees) 
       if(feed.validate()) { 
        feed.save() 
       } else { 
        log.warn "Problem with validation " + feed.errors.allErrors.dump() 
       } 
       log.info '#posts: ' + feed.posts.size() <---- THIS SEEMS TO WORK. I SEE SIZE GO DOWN 

      } 

      // repeated for FeedSegment... 

     } 
    } 

當我嘗試刪除ItemCollection我碰到下面的堆棧跟蹤:

2012-10-02 18:09:21,499 [http-bio-9090-exec-1] INFO feeds.Posting - Deleting: com.broadcastr.feeds.Posting : 2 
2012-10-02 18:09:21,507 [http-bio-9090-exec-1] INFO feeds.Posting - found feeds: [<[email protected] category=Arts & Entertainment city=New York City posts=[com.broadcastr.feeds.Posting : 1, com.broadcastr.feeds.Posting : 2] lastUpdated=2012-10-02 17:27:48.819 segments=[] jsonMetaData=null errors=null id=1 version=2>] 
2012-10-02 18:09:21,507 [http-bio-9090-exec-1] INFO feeds.Posting - #posts: 2 
2012-10-02 18:09:21,507 [http-bio-9090-exec-1] INFO feeds.Posting - #posts: 1 
2012-10-02 18:09:21,508 [http-bio-9090-exec-1] INFO feeds.Posting - found feeds: [<[email protected] category=Arts & Entertainment city=New York City posts=[com.broadcastr.feeds.Posting : 1] lastUpdated=2012-10-02 17:27:48.819 segments=[] jsonMetaData=null errors=grails.validation.ValidationErrors: 0 errors id=1 version=2>] 
2012-10-02 18:09:21,510 [http-bio-9090-exec-1] WARN util.JDBCExceptionReporter - SQL Error: 23503, SQLState: 23503 
| Error 2012-10-02 18:09:21,510 [http-bio-9090-exec-1] ERROR util.JDBCExceptionReporter - Referential integrity constraint violation: "FKFD598F4D2EE471: PUBLIC.ITEM_FEED_POSTING FOREIGN KEY(POSTING_ID) REFERENCES PUBLIC.POSTING(ID)"; SQL statement: 
delete from posting where id=? and version=? [23503-164] 
| Error 2012-10-02 18:09:21,512 [http-bio-9090-exec-1] ERROR events.PatchedDefaultFlushEventListener - Could not synchronize database state with session 
Message: could not delete: [com.broadcastr.feeds.Posting#2] 
    Line | Method 
->> 41 | doCall in DebugFilters$_closure1_closure2_closure5 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
| 195 | doFilter in grails.plugin.cache.web.filter.PageFragmentCachingFilter 
| 63 | doFilter in grails.plugin.cache.web.filter.AbstractFilter 
| 886 | runTask in java.util.concurrent.ThreadPoolExecutor$Worker 
| 908 | run . . in  '' 
^ 680 | run  in java.lang.Thread 
Caused by JdbcSQLException: Referential integrity constraint violation: "FKFD598F4D2EE471: PUBLIC.ITEM_FEED_POSTING FOREIGN KEY(POSTING_ID) REFERENCES PUBLIC.POSTING(ID)"; SQL statement: 
delete from posting where id=? and version=? [23503-164] 
->> 329 | getJdbcSQLException in org.h2.message.DbException 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
| 169 | get  in  '' 
| 146 | get . . in  '' 
| 398 | checkRow in org.h2.constraint.ConstraintReferential 
| 415 | checkRowRefTable in  '' 
| 291 | checkRow in  '' 
| 862 | fireConstraints in org.h2.table.Table 
| 879 | fireAfterRow in  '' 
| 99 | update . in org.h2.command.dml.Delete 
| 73 | update in org.h2.command.CommandContainer 
| 226 | executeUpdate in org.h2.command.Command 
| 143 | executeUpdateInternal in org.h2.jdbc.JdbcPreparedStatement 
| 129 | executeUpdate in  '' 
| 105 | executeUpdate in org.apache.commons.dbcp.DelegatingPreparedStatement 
| 41 | doCall . in DebugFilters$_closure1_closure2_closure5 
| 195 | doFilter in grails.plugin.cache.web.filter.PageFragmentCachingFilter 
| 63 | doFilter in grails.plugin.cache.web.filter.AbstractFilter 
| 886 | runTask in java.util.concurrent.ThreadPoolExecutor$Worker 
| 908 | run . . in  '' 
^ 680 | run  in java.lang.Thread 
| Error 2012-10-02 18:09:21,516 [http-bio-9090-exec-1] ERROR servlet.GrailsDispatcherServlet - HandlerInterceptor.afterCompletion threw exception 
Message: could not delete: [com.broadcastr.feeds.Posting#2]; SQL [delete from posting where id=? and version=?]; constraint ["FKFD598F4D2EE471: PUBLIC.ITEM_FEED_POSTING FOREIGN KEY(POSTING_ID) REFERENCES PUBLIC.POSTING(ID)"; SQL statement: 
delete from posting where id=? and version=? [23503-164]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not delete: [com.broadcastr.feeds.Posting#2] 
    Line | Method 
->> 41 | doCall in DebugFilters$_closure1_closure2_closure5 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
| 195 | doFilter in grails.plugin.cache.web.filter.PageFragmentCachingFilter 
| 63 | doFilter in grails.plugin.cache.web.filter.AbstractFilter 
| 886 | runTask in java.util.concurrent.ThreadPoolExecutor$Worker 
| 908 | run . . in  '' 
^ 680 | run  in java.lang.Thread 
Caused by ConstraintViolationException: could not delete: [com.broadcastr.feeds.Posting#2] 
->> 41 | doCall in DebugFilters$_closure1_closure2_closure5 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
| 195 | doFilter in grails.plugin.cache.web.filter.PageFragmentCachingFilter 
| 63 | doFilter in grails.plugin.cache.web.filter.AbstractFilter 
| 886 | runTask in java.util.concurrent.ThreadPoolExecutor$Worker 
| 908 | run . . in  '' 
^ 680 | run  in java.lang.Thread 
Caused by JdbcSQLException: Referential integrity constraint violation: "FKFD598F4D2EE471: PUBLIC.ITEM_FEED_POSTING FOREIGN KEY(POSTING_ID) REFERENCES PUBLIC.POSTING(ID)"; SQL statement: 
delete from posting where id=? and version=? [23503-164] 
->> 329 | getJdbcSQLException in org.h2.message.DbException 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
| 169 | get  in  '' 
| 146 | get . . in  '' 
| 398 | checkRow in org.h2.constraint.ConstraintReferential 
| 415 | checkRowRefTable in  '' 
| 291 | checkRow in  '' 
| 862 | fireConstraints in org.h2.table.Table 
| 879 | fireAfterRow in  '' 
| 99 | update . in org.h2.command.dml.Delete 
| 73 | update in org.h2.command.CommandContainer 
| 226 | executeUpdate in org.h2.command.Command 
| 143 | executeUpdateInternal in org.h2.jdbc.JdbcPreparedStatement 
| 129 | executeUpdate in  '' 
| 105 | executeUpdate in org.apache.commons.dbcp.DelegatingPreparedStatement 
| 41 | doCall . in DebugFilters$_closure1_closure2_closure5 
| 195 | doFilter in grails.plugin.cache.web.filter.PageFragmentCachingFilter 
| 63 | doFilter in grails.plugin.cache.web.filter.AbstractFilter 
| 886 | runTask in java.util.concurrent.ThreadPoolExecutor$Worker 
| 908 | run . . in  '' 
^ 680 | run  in java.lang.Thread 

回答

0

原來還有另一張表格被引用,我沒有處理。澄清上面的答案 - withNewSession是在這裏使用的正確的習慣用法,你不想在beforeDelete方法中保存(flush:true)。

0

你可能不應該使用兩個會話。我不認爲hibernate會保證在你的beforeDelete處理程序中創建的會話會在Posting對象被刪除之前被刷新。如果您不需要兩個單獨的會話,請使用withSession而不是withNewSession

+0

將嘗試。我讀過的所有內容都表明,你必須在beforeDelete中使用withNewSession。 –

+0

另一種可能的解決方案是確保刷新新會話中的更改。嘗試使用'save(flush:true)'而不是'save()'。 – ataylor

+0

是的,根據文檔http://grails.org/doc/latest/guide/GORM.html這一切都發生在刷新過程中,所以save(flush:true)真的很糟糕,你應該使用withNewSession() –