サンプルソース
ドメイン
Person.groovy
package sqltest
class Person {
String name
Integer age
Editor editor
static hasMany = [hobbies:Hobby]
static constraints = {
}
static mapping = {
version: false
}
static adults = where {
age >= 20
}
def sayHello() {
"Hello! I am ${name}"
}
String toString() {
"${name}(${age})"
}
}
Hoggy.groovy
package sqltest
class Hobby {
String name
static constraints = {
}
static mapping = {
version: false
}
}
Editor.groovy
package sqltest
class Editor {
String name
static constraints = {
}
static mapping = {
version:false
}
}
テストデータ登録
BootStrap.groovy
import sqltest.Editor
import sqltest.Hobby
import sqltest.Person
class BootStrap {
def init = { servletContext ->
environments {
development {
def h1 = new Hobby(name:"Hobby-1").save(flush:true)
def h2 = new Hobby(name:"Hobby-2").save(flush:true)
def h3 = new Hobby(name:"Hobby-3").save(flush:true)
def e1 = new Editor(name:"vim").save(flush:true)
def e2 = new Editor(name:"emacs").save(flush:true)
def p1 = new Person(name:"koji-1", age: 19, editor: e1).addToHobbies(h1).save(flush:true)
def p2 = new Person(name:"koji-2", age: 20, editor: e2).addToHobbies(h2).save(flush:true)
def p3 = new Person(name:"koji-3", age: 99, editor: e1).addToHobbies(h1).addToHobbies(h2).addToHobbies(h3).save(flush:true)
def p4 = new Person(name:"koji-1", age: 20, editor: e2).addToHobbies(h2).save(flush:true)
p1.addToHobbies(h3).save(flush:true)
p2.addToHobbies(h3).save(flush:true)
p1.removeFromHobbies(h3)
}
test {
}
production {
}
}
}
def destroy = {
}
}
使い方
HelloController
package sqltest
import grails.gorm.DetachedCriteria
class HelloController {
def where () {
DetachedCriteria a = Person.where {
name == "koji-2"
}
Person p = a.find()
render p.sayHello()
}
// ドキュメントにはわかりやすく書かれていないけど、Groovyの正規表現っぽい構文で==~と=~
// が使えるけど、利用できるのは結局SQLのlike構文なので、正規表現が使えるわけではない。
def where2() {
DetachedCriteria query = Person.where {
name ==~ /koji-%/
}
render query.list().size()
}
// 少し複雑な条件になると、Groovyライクな条件指定ができるwhereクエリのほうが
// ダイナミックファインダーよりスマートかも?
def where3() {
DetachedCriteria query = Person.where {
(name == "koji-1" && age == 20) || age == 99
}
render query.list()
}
// whereクエリは遅延評価なので、ドメインの中に事前に用意しておくことも可能。
// 結果的に名前をつけることになるので、どういったデータが抽出されるのかわかりやすくなる。
def where4() {
render Person.adults.list()
}
// 関連を持っているドメインも検索できる。
def where5() {
Editor e = Editor.findByName("vim")
DetachedCriteria query = Person.where {
editor.name == e.name
// こっちもOK
//editor.name == Editor.findByName("vim").name
}
render query.list()
}
// ただし1対多だとsizeしか使えない。。。
// 1対多の扱いはダイナミックファインダーでも微妙に挙動が理解しづらい。
def where6() {
DetachedCriteria query = Person.where {
hobbies.size() >= 2
}
render query.list()
}
// まず20歳のユーザの一覧を取得する。そのユーザたちの名前と一致するユーザを抜き出してくる。
// なので、当然未成年者が含まれる可能性がある。
def where7() {
DetachedCriteria query = Person.where {
name in where {age == 20}.name
}
render query.list()
}
// 成人ユーザの一覧を取得し、、その中から最も若い年齢を取得する。
// その年齢と一致するユーザの一覧を取得する。
// つまり、成人ユーザで最も若いユーザの一覧が取得される。
def where8() {
DetachedCriteria query = Person.where {
age == where { age > 19 }.min('age')
}
render query.list()
}
}