[Grails]whereクエリの使い方サンプル

#サンプルソース
##ドメイン
```groovy: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})"
    }
}
```

```groovy:Hoggy.groovy
package sqltest

class Hobby {

    String name
    static constraints = {
    }
    static mapping = {
        version: false
    }
}

```

```groovy:Editor.groovy
package sqltest

class Editor {

    String name

    static constraints = {
    }
    static mapping = {
        version:false
    }
}
```

##テストデータ登録
```groovy: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 = {
    }

}
```
#使い方
```groovy: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しか使えない。。。
    // １対多の扱いはダイナミックファインダーでも微妙に挙動が理解しづらい。
    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()
    }
}

```