7

私はgrailsプラグインを書いていますが、保存後にロジックを実行するには、ドメインのsave()メソッドにフックする必要があります。複数のドメインクラスでこれを行う必要があります。プラグインユーザーがGORMでHibernateを使用していない場合に、Hibernateイベントを回避しようとしています。

私は多くのことを試みましたが、以下は私が働くのに最高のチャンスがあったはずだったと思うものです。すべての場合において、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']
4

6 に答える 6

6

プラグイン/アプリの初期化中に save() メソッドへの参照を正常に取得できませんでした。どうしてか分かりません。代わりに、挿入、更新、および削除の後に休止状態イベントのリスナーを作成することにしました。監査ログ プラグインに関する Sean Hartsock によるこの投稿は、それを行うための完璧な入門書です。

リスナーの要点は次のとおりです。

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
}

一日の終わりにはかなりシンプル...

于 2009-12-27T00:00:53.640 に答える
2

FalconeUtilプラグインをご覧ください。このプラグインを使用すると、Hibernateイベントにフックできます(ページ下部のドキュメントを参照してください)。これがまさにあなたが望むものであるかどうかはわかりませんが、いくつかのヒントが得られるかもしれません。

追伸!プラグインはまだGrails1.2で動作しないと思います。

于 2009-12-25T16:53:25.723 に答える
2

メタクラスに追加された 3 つの異なるバージョンの保存があります。

save(Map)
save(Boolean)
save()

テストでどちらを呼び出していますか? それぞれにコードを追加する必要があります。

確認すべきもう 1 つのことは、metaClass に 3 つのメソッドを追加する hibernate プラグインの後にプラグインが実行されているかどうかです。

乾杯

リー

于 2009-12-24T03:21:33.193 に答える
2

これは時期尚早の最適化の問題です。Groovy の古いバージョンでは、MetaClass マングリングに重大なペナルティが課せられたため、GORM は必要性を検出するまですべての魔法を追加しません。

最も簡単な解決策は、プラグインを GORM Labs に依存させることです (私はそこで回避しています)。別の解決策は、methodMissing を手動でトリガーすることです (これは、私が行った作業を複製することになります)。私がそれをどのように達成したかについての詳細は、GORM Labs のドキュメントを参照してください。

于 2009-12-28T16:33:08.293 に答える
1

これは、作業単位を所有するサービス クラスに追加するのが最善ではないでしょうか? これは、Spring/Grails の通常のイディオムがそのようなロジックを持つ場所です。保存をまったく変更する必要はありません。

于 2009-12-24T01:30:49.597 に答える
1

追加の GORM メソッドは、それらのいずれかへの最初の呼び出しで遅延初期化されます。それらを初期化するにはdoWithDynamicMethods、ドメイン クラスの静的メソッドの 1 つを呼び出すだけです。

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() メソッドが利用可能になります。これは起動時に呼び出されるため、単一のカウントはそれほど問題にはなりません。

于 2010-08-04T20:16:18.287 に答える