Groovy dynamisch aufgerufen Klasse und finden Methode nicht funktioniert?
-
26-09-2019 - |
Frage
ich versuche, eine dynamische Abfrage ähnlich wie erstellen:
def domain = DomainName
def ids = 1
def domainClass = "$domain" as Class
domainClass.find("from ${domain} as m where m.job = ${ids} ").id
Aber es funktioniert nicht.
Wenn ich dies versuche, alles ist in Ordnung:
def domain = DomainName
def ids = 1
DomainName.find("from ${domain} as m where m.job = ${ids} ").id
Wie kann ich dynamische Domain-Klassennamen finden?
Lösung
Der einfachste Weg ist es, die getDomainClass
Methode zu verwenden:
String domainClassName = 'com.foo.bar.Person'
def ids = 1
def domainClass = grailsApplication.getDomainClass(domainClassName).clazz
domainClass.find("from $domainClassName as m where m.job = ${ids} ").id
Beachten Sie, wenn Sie versuchen, eine einzelne Instanz von id, Verwendung get
zu bekommen:
long id = 1234
def person = domainClass.get(id)
und wenn Sie mehrere Instanzen erhalten möchten und Sie haben eine Liste von IDs, können Sie getAll verwenden
def ids = [1,2,3,4,5]
def people = domainClass.getAll(ids)
Auch ist es eine wirklich schlechte Idee Verwendung gstrings mit Eigenschaftswerten eingebettet - Google 'SQL Injection'
Zum Beispiel eine Person, die von Benutzernamen zu finden:
String username = 'foo'
def person = domainClass.find(
"from $domainClassName as m where m.username=:username",
[username: username])
Andere Tipps
Es soll möglich sein, dies zu tun, indem sie ausdrücklich die GroovyClassLoader mit:
def domain = "DomainName"
def c = new GroovyClassLoader().loadClass(domain)
c.find('...').id
Der beste Weg, um eine Domain-Klasse dynamisch zu bekommen, ist durch das GrailsApplication Objekt. Beispiel:
import org.codehaus.groovy.grails.commons.ApplicationHolder
def domainName = "full.package.DomainName"
def domainGrailsClass = ApplicationHolder.application.getArtefact("Domain", domainName)
def domainClass = domainGrailsClass.getClazz()
domainClass.find("from ${domainGrailsClass.name} as m where m.job = ${ids}").id
Sie können auch Class.forName()
verwenden so wie man es in Java. Verwenden Sie die 3 Parameterversion und übergibt im aktuellen Thread-Kontext-Klassenlader:
import grails.util.GrailsNameUtils
def domainName = "full.package.DomainName"
def domainClass = Class.forName(domainName, true, Thread.currentThread().getContextClassLoader())
domainClass.find("from ${GrailsNameUtils.getShortName(domainName)} as m where m.job = ${ids}").id
Classloader sind ein hässliches Thema in Java und JVM-Frameworks. In Grails, Sie wollen fast immer den Thread-Kontext verwenden Classloader. Aber noch besser ist es, die GrailsApplication Schnittstelle zu verwenden und das Problem ganz zu vermeiden.
GrailsClassUtils.getShortName(DomainName)
den Namen der Klasse erhalten, so sollte diese Arbeit ... wenn ich die Frage
verstandendef domainClassName = GrailsClassUtils.getShortName(DomainName)
def ids = 1
DomainName.find("from ${domainClassName} as m where m.job = ${ids} ").id