【问题标题】:"Overloading" standard GORM CRUD methods“重载”标准 GORM CRUD 方法
【发布时间】:2010-12-12 10:54:57
【问题描述】:

想要执行以下操作:

引导带 { def init = {servletContext -> ........... MyDomainClass.metaClass.save = {-> 委托.extraSave() //////// 如何在这里调用原始的save()? } } ………… }

附: MyDomainClass#extraSave 定义为public void extraSave(){.....}

【问题讨论】:

    标签: grails groovy overloading crud


    【解决方案1】:

    首先,Bootstrap.groovy 可能不是进行这种元编程的最佳场所。这种方法的问题在于,对类的更改将在应用程序启动时应用,但在重新加载应用程序时您可能会丢失这些更改。显然,这只是开发过程中的一个问题,如果您不介意每次进行更改时都重新启动服务器,那么这根本不是问题,但我敢打赌这很快就会成为一个主要的烦恼。为了在重新加载应用程序时也应用更改,您应该将元编程移动到一个插件中,您可以在其中挂钩到 onChange 应用程序生命周期事件。

    所以步骤是:

    • 创建插件
    • 在插件描述符的 doWithDynamicMethodsonChange 闭包中进行元编程

    这是一个完整的示例,我在所有控制器类上“覆盖”了 chain() 方法。为域类的 save() 方法做同样的代码应该只需要一些明显的替换,例如使用application.domainClasses 而不是application.controllerClasses

    def doWithDynamicMethods = {ctx ->
    
        application.controllerClasses.each {controller ->
            replaceChain(controller)
        }
    }
    
    def onChange = {event ->
        if (application.isArtefactOfType(ControllerArtefactHandler.TYPE, event.source)) {
            def clz = application.getControllerClass(event.source?.name)
            replaceChain(clz)
        }
    }
    
    private replaceChain(controllerClass) {
    
        // Save a  reference to the grails chain() method
        def grailsChain = controllerClass.metaClass.pickMethod("chain", [Map] as Class[])
    
        controllerClass.metaClass.chain = {Map params ->
    
            println "My code to execute before chain goes here"
    
            // Invoke the grails chain() method
            grailsChain.invoke(delegate, [params] as Object[])
    
            println "My code to execute after chain goes here"
        }
    }
    

    【讨论】:

      【解决方案2】:

      为什么不为此目的利用 GORM 事件?在域类中:

      def extraSave() {
          // ...
      }
      
      def beforeInsert = {
          extraSave()
      }
      
      def beforeUpdate = {
          extraSave()
      }
      

      恕我直言,这是一种更清洁的方法。文档可以在here找到

      【讨论】:

      • 这种方法的一个缺点是您需要将 extraSave() 添加到每个域类的事件处理程序中。元编程方法只需要您在一个地方定义/调用 extraSave()
      • 当然,在处理此类事情时,我仍然更喜欢基于 EntityInterceptor 的方法。覆盖 GORM 方法可以是真正的 PITA。
      • 顺便说一句。使用 EntityInterceptor 只需创建 org.hibernate.EmptyInterceptor 的子类并将其注册为 grails-app/conf/spring/resources.groovy 中名为“entityInterceptor”的 bean(从 Grails 1.2 开始 - 在旧版本中也可以,但拦截器的注册工作量更大)
      • 我在尝试超载save() 之前就尝试过这种方法。它的问题是即使处理程序在save()saveOrUpdate() 中也被调用,所以我需要用.withNewSession 包装我的extraSave()(这会导致其他问题,因为我正在上一层进行批处理),或者想点别的。
      【解决方案3】:

      不确定以下是否可行,但这可能是一个解决方案:

      MyDomainClass.metaClass.origSave = MyDomainClass.metaClass.save
      MyDomainClass.metaClass.save = {-> 
         delegate.extraSave()
         delegate.origSave()
      }
      

      如果上述方法有效,请给我反馈...

      【讨论】:

      • 昨天试过了。不能说origSave 是元类属性或其他东西而不是闭包,类似的东西。尝试了不同的调用方式:origSave()origSave.call()
      猜你喜欢
      • 2011-12-08
      • 1970-01-01
      • 1970-01-01
      • 2020-06-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-31
      • 2014-11-10
      相关资源
      最近更新 更多