2010-10-12 35 views
0

我正在將一個Grails應用程序從Oracle移植到MySQL數據庫。原始的Oracle版本是一個遺留數據庫,它使用了一些複雜的視圖,利用了Oracle不具備的MySQL INSTEAD OF INSERT OR UPDATE功能。作爲解決方法,我在指向這些視圖的域類上實現了插入和更新方法。例如,由自動失敗的自定義插入和更新方法保存

class AdminUser { 
    //... 
    def update() { 
     if(this.validate()) { 
      Sql sql = Utils.getHibernateSql() 

      sql.execute(
       "update table_x ...", 
       [...] 
      ) 

      sql.execute(
       "update table_y ...)", 
       [...] 
      ) 

      sql.execute(
       "update table_z ...", 
       [...] 
      ) 

      return true 
     } 

     return false 
    } 
    //... 
} 

這裏是我目前運行到這個問題的描述:

  1. 內的服務方法使用我AdminUser.get
  2. 我修改加載ADMINUSER的實例加載的實例和調用更新(),都顯得很好
  3. 一旦服務方法完成執行,由於調用實例上的某些保存事件而引發異常。

如何防止在步驟(3)中發生的魔法保存(我最近在某處讀取Grails會自動保存修改後的Domain類實例,該類實例在退出服務方法時尚未保存,但我可以現在似乎沒有找到與該資源的鏈接)?

回答

2

您將修改的實例留在具有髒字段的休眠會話中。當hibernate會話被刷新時,它將嘗試用通常的save()方法再次保存該對象。

一種解決方案是在手動保存更改後,從休眠會話中丟棄對象。例如:

def update() { 
    if(this.validate()) { 
     Sql sql = Utils.getHibernateSql() 

     sql.execute(
      "update table_z ...", 
      [...] 
     ) 

     ... 

     this.discard() // remove the object from the hibernate session 
     return true 
    } 

此外,您可以添加到您的Config.groovy中要求的對象被明確地保存:

hibernate.flush.mode="manual" 
+0

優秀,解決了它,謝謝! – 2010-10-12 17:56:18

0

如果你使用read()而不是get()方法,然後該對象不會自動保持更改。您仍然可以顯式調用save(),但OpenSessionInView攔截器刷新所有未保存的髒實例的標準行爲將跳過使用read()加載的實例。

+0

我不確定read()是否合適:我需要修改,驗證並對域實例執行手動插入/更新。從你所說的話看來,即使使用read(),我仍然可以做所有這些事情,但我假設如果我試圖修改它,對象會拋出異常或其他東西。但無論如何,我對@ataylor給出的解決方案感到更加舒適。謝謝。 – 2010-10-12 18:01:45

+1

正如我所說的,你仍然可以直接調用save()(和/或validate()),它會一直存在。但它不會自動持續。 – 2010-10-12 18:42:45