2009-12-24 82 views
7

我正在寫一個grails插件,我需要掛鉤到域save()方法來保存後做一些邏輯。我需要在多個域類中執行此操作。我試圖在插件用戶不使用HORM和GORM的情況下避免使用hibernate事件。掛鉤到Grails域對象保存()

我已經嘗試了很多東西,但以下是我認爲應該有最好的工作機會。在所有情況下,grailsS​​avenull。我怎樣才能做到這一點?

def doWithDynamicMethods = { ctx -> 
    application.domainClasses.each { dc -> 
     def grailsSave = dc.metaClass.pickMethod('save', [Map] as Class[]) 

     domainClass.metaClass.save = { Map params -> 
     grailsSave.invoke(delegate, [params] as Object[]) 
     println "Saved object, now do my thing" 
     //... 
     } 
    } 
} 

,我有以下我* Plugin.groovy類設置:

def dependsOn = [domainClass: '1.1 > *', hibernate: '1.1 > *'] 
def loadAfter = ['hibernate'] 

回答

6

我在plugin/app初始化期間無法成功獲取對save()方法的引用;我不知道爲什麼。相反,我決定在插入,更新和刪除後爲hibernate事件創建一個偵聽器。 Sean Hartsock關於Audit Logging插件的post是一個完美的入門書。

這裏的監聽器的要點:

class MyListener implements PostInsertEventListener, PostUpdateEventListener, PostDeleteEventListener, Initializable { 

     public void onPostInsert(final PostInsertEvent event) { 
      // logic after insert 
      return 
     } 

     public void onPostUpdate(final PostUpdateEvent event) { 
      // logic after update 
      return 
     } 

     public void onPostDelete(final PostDeleteEvent event) { 
      // logic after delete 
      return 
     } 


     public void initialize(final Configuration config) { 
      return 
     } 
    } 

然後在* GrailsPlugin.groovy:

def doWithApplicationContext = { applicationContext -> 

    // add the event listeners for reindexing on change 
    def listeners = applicationContext.sessionFactory.eventListeners 
    def listener = new MyListener() 

    ['postInsert', 'postUpdate', 'postDelete'].each({ 
     addEventTypeListener(listeners, listener, it) 
    }) 

} 


// copied from http://hartsock.blogspot.com/2008/04/inside-hibernate-events-and-audit.html 
private addEventTypeListener(listeners, listener, type) { 
    def typeProperty = "${type}EventListeners" 
    def typeListeners = listeners."${typeProperty}" 

    def expandedTypeListeners = new Object[typeListeners.length + 1] 
    System.arraycopy(typeListeners, 0, expandedTypeListeners, 0, typeListeners.length) 
    expandedTypeListeners[-1] = listener 

    listeners."${typeProperty}" = expandedTypeListeners 
} 

在一天結束的時候相當簡單...

+0

肖恩和他的審計記錄插件岩石。 – 2009-12-28 16:39:03

+0

感謝分享!我一直懶惰地看着我的自我。 – Kimble 2009-12-28 22:23:17

1

這是不是最好加入到擁有工作單位的服務類?這就是通常的Spring/Grails成語會有這樣的邏輯的地方。你根本不需要修改保存。

+0

儘管我正在構建一個供其他人使用的插件。我的邏輯很可能在服務中,但它需要着火的一點是保存。謝謝 – mbrevoort 2009-12-24 02:16:47

+0

把直接與域相關的一堆邏輯委託給另一個層的想法是Spring中最令人頭疼的問題之一,這就是爲什麼Java在複雜性體現出戀物癖的聲譽。 – 2009-12-28 16:34:27

+0

單個域對象如何知道它是什麼時候它是大型工作單元的一部分,什麼時候不是? – duffymo 2009-12-28 17:16:17

2

有三種不同的版本保存添加到元類,

save(Map) 
save(Boolean) 
save() 

哪一個是你在測試打電話?您需要將代碼添加到每個代碼中。

另一件事是檢查你的插件是否是Hibernate插件它增加了三種方法來元類

歡呼

+0

謝謝李, 我覺得我有問題迫使插件加載後休眠。如果我在doWithDynamicMethods中運行,所有嘗試調用pickMethod的值都是null。如果我在grails控制檯中運行,它們不是null。 我有這個在我的插件,但沒有運氣: def dependsOn = [domainClass:'1.1> *',hibernate:'1.1> *'' def loadAfter = ['hibernate'] – mbrevoort 2009-12-24 04:43:11

+0

嗯loadAfter是你想要的 - 它是否需要是 static loadAfter = ['hibernate'] – leebutts 2009-12-24 06:46:03

+0

靜態也不起作用。奇怪的是,我剛剛注意到Robert Fischer試圖在他的GORM Labs插件中用save()做類似的事情,但在之前的版本中評論過代碼,並且在最近的版本中並不存在。任何想法如何解決這個不同? – mbrevoort 2009-12-24 15:12:40

2

運行後看看在Falcone Util插件。這個插件允許你鉤入Hibernate事件(參見頁面底部的文檔)。我不知道這是否正是你想要的,但你可能會得到一些提示。

Ps!我不認爲插件與Grails 1.2一起工作。

+0

感謝隊友,那個插件看起來不錯。如果這種類型的事件功能在覈心中可用,將會非常棒。 – mbrevoort 2009-12-26 17:23:46

2

這是一個過早優化的問題:舊版本的Groovy嚴重懲罰了MetaClass的變形,所以GORM在檢測到需要之前不會添加所有的魔法。

最簡單的解決方案是讓你的插件取決於GORM實驗室(我在那裏工作)。另一種解決方案是手動觸發methodMissing(這將重複我所做的工作)。有關我如何實現這一點的詳細信息,請參閱GORM實驗室文檔。

1

其他GORM方法在首次調用其中的任何一個時被懶惰地初始化。 初始化它們在doWithDynamicMethods簡單地調用你的域類(ES)的靜態方法之一:

def doWithDynamicMethods = { ctx -> 

    application.domainClasses.each { dc -> 

     // call any static method to initialize dynamic gorm methods 
     dc.clazz.count() 

     def grailsSave = dc.metaClass.pickMethod('save', [Map] as Class[]) 
     //... 
    } 
} 

你的save()方法可現在。正如開始時所說的那樣,單次計數不應該成爲一個大問題。