Динамически вызываемый класс Groovy и метод поиска не работают?

Я пытаюсь построить динамический запрос, похожий на:

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

Как я могу использовать динамическое имя класса домена с поиском?


person Fabien Barbier    schedule 19.11.2010    source источник


Ответы (4)


Самый простой способ — использовать метод 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

Обратите внимание: если вы пытаетесь получить один экземпляр по идентификатору, используйте get:

long id = 1234
def person = domainClass.get(id)

и если вы хотите получить несколько экземпляров и у вас есть список идентификаторов, вы можете использовать getAll

def ids = [1,2,3,4,5]
def people = domainClass.getAll(ids)

Кроме того, ДЕЙСТВИТЕЛЬНО плохая идея использовать GStrings со встроенными значениями свойств - Google 'SQL Injection'

Например, чтобы найти человека по имени пользователя:

String username = 'foo'
def person = domainClass.find(
    "from $domainClassName as m where m.username=:username",
    [username: username])
person Burt Beckwith    schedule 20.11.2010
comment
У меня есть общее представление. Все языки программирования имеют своего рода ключевые слова/ограниченные слова, задокументированные в любом введении. Groovy должен документировать в компактной форме список заводских перегруженных методов. Что ты думаешь? - person Jacek Cz; 20.08.2015

Вы должны иметь возможность сделать это, явно используя GroovyClassLoader:

def domain = "DomainName"
def c = new GroovyClassLoader().loadClass(domain)
c.find('...').id
person ig0774    schedule 19.11.2010
comment
В приложении Grails лучше использовать GrailsAwareClassLoader вместо GroovyClassLoader. GrailsAwareClassLoader работает так же, но также поддерживает динамические инъекции. В этом конкретном случае доменный класс уже будет загружен, и GroovyClassLoader просто вернет ссылку, уже загруженную загрузчиком Grails, но в целом таким образом вы можете внести некоторые неожиданные ошибки. - person ataylor; 20.11.2010

Лучший способ динамически получить класс домена — использовать объект 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() так же, как в Java. Используйте версию с 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. В Grails вы почти всегда хотите использовать загрузчик классов контекста потока. Но еще лучше использовать интерфейс GrailsApplication и вообще избежать этой проблемы.

person ataylor    schedule 20.11.2010

используйте GrailsClassUtils

GrailsClassUtils.getShortName(DomainName)

чтобы получить имя класса, так что это должно работать... если я понял вопрос

def domainClassName = GrailsClassUtils.getShortName(DomainName)
def ids = 1
DomainName.find("from ${domainClassName} as m where m.job = ${ids} ").id
person Aaron Saunders    schedule 19.11.2010