Groovy Динамически вызываемый класс и найти метод не работает?
-
26-09-2019 - |
Вопрос
Я пытаюсь построить динамический запрос, похожий на:
def domain = DomainName
def ids = 1
def domainClass = "$domain" as Class
domainClass.find("from ${domain} as m where m.job = ${ids} ").id
Но это не работает.
Если я пробую это, все в порядке:
def domain = DomainName
def ids = 1
DomainName.find("from ${domain} as m where m.job = ${ids} ").id
Как я могу использовать имя динамического класса домена с нахождением?
Решение
Самый простой способ - использовать getDomainClass
Метод:
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
Обратите внимание, что если вы пытаетесь получить один экземпляр по ID, используйте get
:
long id = 1234
def person = domainClass.get(id)
И если вы хотите получить несколько экземпляров, и у вас есть список идентификаторов, вы можете использовать Gentall
def ids = [1,2,3,4,5]
def people = domainClass.getAll(ids)
Также это В САМОМ ДЕЛЕ Плохая идея использовать Gtrings с значениями свойств встроенным - Google 'SQL Inurion'
Например, чтобы найти человека по имени пользователя:
String username = 'foo'
def person = domainClass.find(
"from $domainClassName as m where m.username=:username",
[username: username])
Другие советы
Вы должны сделать это, явно используя GroovyClassLoader:
def domain = "DomainName"
def c = new GroovyClassLoader().loadClass(domain)
c.find('...').id
Лучший способ динамически получить класс домена - через объект GrailSApplication. Пример:
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
Вы также можете использовать Class.forName()
Так же, как вы бы в Яве. Используйте версию 3 параметра и пропустите текущий погрузчик контекстно-потока:
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
Классические загрузчики являются уродливой темой в Java и JVM Frameworks. В Граалях вы почти всегда хотите использовать CloseLoader Context Context. Но еще лучше состоит в том, чтобы использовать интерфейс GrailSApplication и вообще избегать проблемы.
использовать Grailsclassutils.
GrailsClassUtils.getShortName(DomainName)
Чтобы получить название класса, так что это должно работать ... Если я понял вопрос
def domainClassName = GrailsClassUtils.getShortName(DomainName)
def ids = 1
DomainName.find("from ${domainClassName} as m where m.job = ${ids} ").id