2016-06-25 13 views
0

Ich möchte das Konzept der Trigger Objekte in Grails für meine Domain-Klassen implementieren. Grails erlaubt mir, Methoden wie beforeInsert() in meinen Domain-Klassen zu handle insert, update and delete events zu definieren, ähnlich wie SQL-Datenbanken das Konzept der Datenbank-Trigger haben. Aber um Bedenken zu trennen, möchte ich die gesamte Trigger-Logik außerhalb der Domain-Klasse verschieben.GORM Trigger-Muster in Grails 2.5.4

Idealerweise kann ich einfach eine static Liste von Trigger-Klassen in meiner Domain-Klasse definieren und dann die in der beforeInsert()-Methode durchlaufen. Beispielcode unten gezeigt.

static beforeInsertTriggers = [AccountNameTrigger, AccountDumpTrigger] 

def beforeInsert() { 
    for (Class<Trigger> triggerClass : beforeInsertTriggers) { 
     triggerClass.newInstance().using(this).execute() 
    } 
} 

Ich habe erstellt ein sample Grails 2.5.4 project on GitHub darstellt, was ich versuche zu tun. Aber das Problem ist, dass die Auslöser buchstäblich eigenständige Inseln der Logik ohne die Fähigkeit sind, Dienste autowire. Wie kann ich dieses Trigger Muster oder etwas Ähnliches besser einstellen? Also kann ich Dienste und andere Beans in die Trigger Instanzen autowire?

Ich versuche auch, das Design einfach und lesbar zu halten.

  • Vermeiden Sie die Unordnung der Domänenklasse mit Feldern und Eigenschaften, die nicht mit dem Datenmodell zusammenhängen. Für mich bedeutet dies keine autowired Beans in der Domain-Klasse.
  • Definieren Sie die Liste der Trigger mithilfe der Namen der Trigger-Klassen (oder ggf. der Bean-Namen). Dies kann übermäßig idealistisch sein, aber hey ...

Für das, was es wert ist, ein Teil meiner Inspiration kommt auch aus wie Salesforce implements triggers als getrennte Einheiten von in sich geschlossenen Code.

Antwort

0

Registrieren Sie Ihre Trigger als Singleton Bohnen und dort können Sie andere Dienste/Bohnen injizieren. Sie können Ihre benutzerdefinierten Beans über resources.groovy erstellen.

Nehmen wir das Beispiel von AccountDumpTrigger. Ermöglicht eine einfache Änderung machen:

package grails.domain.trigger.demo.triggers 

import grails.domain.trigger.demo.Account 
import org.codehaus.groovy.grails.commons.GrailsApplication 

/** 
* Created by marty on 6/25/16. 
*/ 
class AccountDumpTrigger extends AbstractTrigger<Account> { 

    GrailsApplication grailsApplication 

    @Override 
    void execute() { 
     println grailsApplication.isInitialised() 
     println resource.dump() 
    } 
} 

Und Code in resources.groovy oder in Ihrem Plugins doWithSpring Schließung:

accountDumpTrigger(grails.domain.trigger.demo.triggers.AccountDumpTrigger) { bean -> 
    bean.factoryMethod = 'getInstance' 
    /* 
    either refer each bean individually or you can use: 
    bean.autowire = "byType" 
     OR 
    bean.autowire = "byName" 
    */ 
    grailsApplication = ref("grailsApplication") 
} 

Und in Ihrer Domain:

static beforeInsertTriggers = [AccountDumpTrigger] 

def beforeInsert() { 
    for (Class<Trigger> triggerClass : beforeInsertTriggers) { 
     triggerClass.instance.using(this).execute() 
    } 
} 

Und statt Schreiben Sie Ihren Code innerhalb beforeInsert Sie können auch das gleiche tun, indem Sie eine Implementierung von AbstractPersistenceEventListener registrieren. Auf diese Weise müssen Sie Ihren Code nicht wiederholen. Sie können es auch in eine Elternklasse verschieben.

+0

Vielen Dank für die schnelle und detaillierte Antwort. Muss ich jede Bean manuell mit der 'ref()' Syntax in * resources.groovy * verbinden? Und ich werde auch in die Event-Listener-Option schauen, da das neu für mich ist. –

+0

Ja, wenn Sie Trigger-Klassen innerhalb von src/groovy erstellen. Wenn Sie Ihre Trigger als Service festlegen, müssen Sie dies nicht tun. Wenn Sie sie zu einem Dienst machen, erhalten Sie den zusätzlichen Vorteil der Hibernate-Sitzungs- und Transaktionsverwaltung. –

+0

Warum funktioniert autoWire nicht? Wenn Sie bean.autowire = 'byName' in Ihrer Trigger-Deklaration in resources.groovy setzen, sollten Sie Variablen injizieren, wenn die Namen übereinstimmen. – billjamesdev