挂钩Grails域对象save()

时间:2009-12-24 00:33:42

标签: grails groovy grails-plugin

我正在写一个grails插件,我需要挂钩到域save()方法,以便在保存后做一些逻辑。我需要在多个域类中执行此操作。我试图避免在插件用户没有使用GORM进行休眠的情况下的hibernate事件。

我尝试了很多东西,但下面是我认为应该有最好的工作机会。在所有情况下, grailsS​​ave 都是 null 。我怎么能这样做?

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 个答案:

答案 0 :(得分:6)

我无法在插件/应用初始化期间成功获取对save()方法的引用;我不知道为什么。相反,我决定在插入,更新和删除之后为hibernate事件创建一个监听器。 Sean Hartsock关于审计日志插件的这个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
}

一天结束时相当简单......

答案 1 :(得分:2)

有三种不同版本的保存添加到metaClass,

save(Map)
save(Boolean)
save()

你在测试中打电话给哪一个?您需要为每个代码添加代码。

要检查的另一件事是你的插件是否在hibernate插件之后运行,它将三种方法添加到metaClass

欢呼声

答案 2 :(得分:2)

查看Falcone Util插件。这个插件允许您挂钩Hibernate事件(请参阅页面底部的文档)。我不知道这是不是你想要的,但你可能会得到一些提示。

诗!我认为插件不适用于Grails 1.2。

答案 3 :(得分:2)

这是一个过早优化的问题:旧版本的Groovy严重损害了MetaClass的修改,因此GORM在检测到需要之前不会添加所有的魔法。

最简单的解决方案是让您的插件依赖于GORM实验室(我在那里解决)。另一种解决方案是手动触发methodMissing(这将重复我所做的工作)。有关如何完成此操作的详细信息,请参阅GORM实验室文档。

答案 4 :(得分:1)

这不是最好添加到拥有工作单元的服务类吗?这就是通常的Spring / Grails成语具有这样的逻辑的地方。您根本不需要修改保存。

答案 5 :(得分:1)

其他GORM方法在首次调用任何一个时都会被懒惰地初始化。 要在doWithDynamicMethods中初始化它们,只需调用域类中的一个静态方法:

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()方法现在可用。由于这是在启动时调用的,因此单个计数不应该是一个大问题。