Reference

Domain Classes

addTo

addTo* 方法

目的

为一对多或多对多关系添加域类关系,其中以该方法的后缀的属性名称表示关系的映射属性

示例

def fictBook = new Book(title: "IT")
def nonFictBook = new Book(title: "On Writing: A Memoir of the Craft")
def a = new Author(name: "Stephen King")
             .addToFiction(fictBook)
             .addToNonFiction(nonFictBook)
             .save()

描述

`addTo*`方法是一种动态的方法,使用一个会自动添加实例的关联。它还自动配置双向关系,使双方都设置。

考虑上面例子中使用的这些domain类:

@Entity
class Author implements GormEntity<Author>{
    String name
    static hasMany = [fiction: Book, nonFiction: Book]
}
@Entity
class Book implements GormEntity<Book>{
    String title
    static belongsTo = [author: Author]
}

这个例子创造了一本新的小说类书籍和一本新的非小说类书籍,归属于一个作者。 addToFiction`是一个动态方法,因为 `Fiction 部分表示的`fiction`集合定义在domain类的`hasMany`属性中,同样的关系也表现在 `NonFiction`和`nonFiction`上. 通过调用 `Author`对象的`save()`方法,关联的 `Book`示例也保存入库, 尽管我们没有显示的调用它们的`save()`方法.

此外,调用addTo*方法会初始化关联的集合,并且会设置`Book`的`author`的引用关系。

还有一种更紧凑的方法,该方法接受一个“map”而不是一个域类实例,如下调用,则自动初始化`Book`对象:

def a = new Author(name: "Stephen King")
             .addToFiction(title: "IT")
             .addToNonFiction(title: "On Writing: A Memoir of the Craft")
             .save()

以上代码可以运行,是因为GORM知道addTo被添加类型,可以使用标准的`Map`构造函数来创建实例.

attach

attach方法

目的

将“detached”状态的domain类实例与当前Hibernate会话关联在一起

示例

def b = Book.get(1)
b.title = "Blah"
b.save(flush:true)

b.discard()

...
if (!b.isAttached()) {
    b.attach()
}

描述

Hibernate在持久会话session中管理持久实例。每个请求创建新会话,并在请求结束时关闭。如果一个对象是从会话中获取并放置到一个Web范围如HttpSession,状态将变为“detached”,一旦Hibernate会话session关闭和废弃。你可以使用` attach() `方法重新附加现有的持久化实例对当前请求的Hibernate session。

belongsTo

belongsTo 静态属性

目的

Defines a "belongs to" relationship where the class specified by belongsTo assumes ownership of the relationship. This has the effect of controlling how saves and deletes cascade. The exact behaviour depends on the type of relationship:

  • Many-to-one/one-to-one: saves and deletes cascade from the owner to the dependant (the class with the belongsTo).

  • One-to-many: saves always cascade from the one side to the many side, but if the many side has belongsTo, then deletes also cascade in that direction.

  • Many-to-many: only saves cascade from the "owner" to the "dependant", not deletes.

示例

class Book {
   String title

   static belongsTo = [author: Author]
}

In this example the Book class specifies that it belongs to the Author class, hence when an Author instance is deleted so are all its associated Book instances.

描述

The belongsTo property abstracts the nature of the cascading behaviour in Hibernate. If you want one class to belong to another but not have a back reference, then you can specify a class or a list of classes as the value:

class Book {
    static belongsTo = Author
}

or:

class Book {
    static belongsTo = [Author, Library]
}

Back references, i.e. properties linking back to the owner, can be added in one of two ways:

class Book {
    Author author

    static belongsTo = Author
}

or:

class Book {
    static belongsTo = [author: Author]
}

In these examples, both techniques create an Author property named author. Also, the Map property can specify multiple properties and types if the class belongs to more than one owner.

The belongsTo property is simple and means you don’t have to worry about the Hibernate cascading strategies, but if you need more control over cascading you can use the ORM DSL. This allows fine grained control of cascading updates and deletes.

clearErrors

clearErrors方法

目的

重装domain类的errors列表 . 如果domain类包含绑定或验证的错误时,将非常有用。这些错误可以通过程序纠正。如果不清除错误,验证将继续失败。

示例

def b = new Book(title: "The Shining")
b.validate()
if (b.hasErrors()) {

    // clear the list of errors
    b.clearErrors()

    // fix the validation issues
    b.author = "Stephen King"

    // re-validate
    b.validate()
}

constraints

constraints

Purpose

Allows the definition of declarative validation constraints. See validation in the user guide.

Examples

class Book {

    String title
    Author author

    static constraints = {
        title blank: false, size: 5..150
        author nullable: true
    }
}

Description

Constraints are defined using the declarative constraints DSL as described in the validation section of the user guide. Once evaluated, validation can be applied through the use of the validate method:

def b = new Book()
assert !b.validate()

The static constrainedProperties property is a Map such that the keys in the Map are property names and the values associated with the keys are instances of {apiDocs}grails/validation/ConstrainedProperty.html[ConstrainedProperty]:

def constraintsMap = Book.constrainedProperties
for(entry in constraintsMap) {
    // propertyName is a String
    def propertyName = entry.key

    // constrainedProperty is a ConstrainedProperty
    def constrainedProperty = entry.value

    // ...
}

count

count方法

目的

返回domain类对应的表的记录总数

示例

int bookCount = Book.count()

countBy

countBy*方法

目的

使用domain类中的属性来查询相应记录的数目的动态方法

示例

这是`Book`的domain类:

class Book {
    String title
    Date releaseDate
    String author
}

下面的用法都是可以的:

def c = Book.countByTitle("The Shining")
c = Book.countByTitleAndAuthor("The Sum of All Fears", "Tom Clancy")
c = Book.countByReleaseDateBetween(firstDate, new Date())
c = Book.countByReleaseDateGreaterThanEquals(firstDate)
c = Book.countByTitleLike("%Hobbit%")
c = Book.countByTitleNotEqual("Harry Potter")
c = Book.countByReleaseDateIsNull()
c = Book.countByReleaseDateIsNotNull()

描述

GORM 支持 Dynamic Finders 的概念. `countBy*`方法对符合给定的表达的记录进行计数

下面的操作名称可以被用在各自的动态方法中:

  • LessThan

  • LessThanEquals

  • GreaterThan

  • GreaterThanEquals

  • Between

  • Like

  • Ilike (i.e. ignorecase like)

  • IsNotNull

  • IsNull

  • Not

  • Equal

  • NotEqual

  • And

  • Or

这些操作名称可以被看作关键字, 当您使用这些操作名称作为属性对domain类进行查询时可能会产生困惑. 更多信息请查看 dynamic finders 的用户向导.

createCriteria

createCriteria方法

目的

创建并返回一个 Grails' HibernateCriteriaBuilder 的实例, 用作构建标准化查询.

单元测试时在内存中实现的并不是GORM Hibernate, 如`createCriteria()` 返回的是 CriteriaBuilder 的实例,而不是HibernateCriteriaBuilder的实例.

示例

用作构建criteria的方法 (like, and, or, between 等) 可以从HibernateCriteriaBuilder静态导入 (就像这篇文档下面的例子), 或者写为 "c.like(…​)", "c.between(…​)" 等.

def c = Account.createCriteria()
def results = c.list {
    like("holderFirstName", "Fred%")
    and {
        between("balance", 500, 1000)
        eq("branch", "London")
    }
    maxResults(10)
    order("holderLastName", "desc")
}

要想使用分页, 你还需使用另一个查询来检索匹配结果的总数. 一个较好的方法是将分页值作为criteria方法的参数, 就像下面:

def c = Account.createCriteria()
def results = c.list (max: 10, offset: 10) {
    like("holderFirstName", "Fred%")
    and {
        between("balance", 500, 1000)
        eq("branch", "London")
    }
    order("holderLastName", "desc")
}

因为这个查询包括了分页参数 (max and offset), 它会返回一个含有`getTotalCount()`方法、可以得到分页数据总数的 PagedResultList. 两个查询依然执行,但执行得到的结果集和总数组合在`PagedResultList`中.

println "Rendering ${results.size()} Accounts of ${results.totalCount}"

描述

Criteria queries are a type-safe, advanced way to query that uses a Groovy builder to construct potentially complex queries. It is a much better alternative to using a StringBuilder to dynamically construct an HQL query. Refer to the user guide section on Criteria for usage instructions.

方法相关:

方法 描述

list

The default method; returns all matching rows.

get

Returns a unique result, i.e. just one row. The criteria has to be formed that way, that it only queries one row. This method is not to be confused with a limit to just the first row.

scroll

Returns a scrollable result set

listDistinct

If subqueries or associations are used, one may end up with the same row multiple times in the result set. In Hibernate one would do a "CriteriaSpecification.DISTINCT_ROOT_ENTITY". In Grails one can do it by just using this method.

The listDistinct() method does not work well with the pagination options maxResult and firstResult. If you need distinct results with pagination, we currently recommend that you use HQL. You can find out more information from this blog post.

If you invoke the builder with no method name

c { ... }

the list() method will be invoked automatically. In other words, it’s the equivalent of

c.list { ... }

Below is a node reference for each criterion method:

Node Description Example

between

Where the property value is between two distinct values

between("balance", 500, 1000)

eq

Where a property equals a particular value.

eq("branch", "London")

eq (case-insensitive)

A version of eq that supports an optional 3rd Map parameter to specify that the query be case-insensitive.

eq("branch", "london", [ignoreCase: true])

eqProperty

Where one property must equal another

eqProperty("lastTx", "firstTx")

gt

Where a property is greater than a particular value

gt("balance",1000)

gtProperty

Where one property must be greater than another

gtProperty("balance", "overdraft")

ge

Where a property is greater than or equal to a particular value

ge("balance", 1000)

geProperty

Where one property must be greater than or equal to another

geProperty("balance", "overdraft")

idEq

Where an objects id equals the specified value

idEq(1)

ilike

A case-insensitive like expression

ilike("holderFirstName", "Steph%")

in

Where a property is contained within the specified list of values. Can also be chained with the not method where a property is not contained within the specified list of values. Note: in is a Groovy reserve word, so it must be escaped by quotes.

'in'("age",[18..65]) or not {'in'("age",[18..65])}

isEmpty

Where a collection property is empty

isEmpty("transactions")

isNotEmpty

Where a collection property is not empty

isNotEmpty("transactions")

isNull

Where a property is null

isNull("holderGender")

isNotNull

Where a property is not null

isNotNull("holderGender")

lt

Where a property is less than a particular value

lt("balance", 1000)

ltProperty

Where one property must be less than another

ltProperty("balance", "overdraft")

le

Where a property is less than or equal to a particular value

le("balance", 1000)

leProperty

Where one property must be less than or equal to another

leProperty("balance", "overdraft")

like

Equivalent to SQL like expression

like("holderFirstName", "Steph%")

ne

Where a property does not equal a particular value

ne("branch", "London")

neProperty

Where one property does not equal another

neProperty("lastTx", "firstTx")

order

Order the results by a particular property

order("holderLastName", "desc")

rlike

Similar to like, but uses a regex. Only supported on Oracle and MySQL.

rlike("holderFirstName", /Steph.+/)

sizeEq

Where a collection property’s size equals a particular value

sizeEq("transactions", 10)

sizeGt

Where a collection property’s size is greater than a particular value

sizeGt("transactions", 10)

sizeGe

Where a collection property’s size is greater than or equal to a particular value

sizeGe("transactions", 10)

sizeLt

Where a collection property’s size is less than a particular value

sizeLt("transactions", 10)

sizeLe

Where a collection property’s size is less than or equal to a particular value

sizeLe("transactions", 10)

sizeNe

Where a collection property’s size is not equal to a particular value

sizeNe("transactions", 10)

sqlRestriction

Use arbitrary SQL to modify the resultset

sqlRestriction "char_length(first_name) = 4"

With dynamic finders, you have access to options such as max, sort, etc. These are available to criteria queries as well, but they have different names:

Name Description Example

order(String, String)

Specifies both the sort column (the first argument) and the sort order (either asc or desc).

order "age", "desc"

firstResult(int)

Specifies the offset for the results. A value of 0 will return all records up to the maximum specified.

firstResult 20

maxResults(int)

Specifies the maximum number of records to return.

maxResults 10

cache(boolean)

Indicates if the query should be cached (if the query cache is enabled).

cache 'true'

Criteria also support the notion of projections. A projection is used to change the nature of the results. For example the following query uses a projection to count the number of distinct branch names that exist for each Account:

def c = Account.createCriteria()
def branchCount = c.get {
    projections {
        countDistinct "branch"
    }
}

The following table summarizes the different projections and what they do:

Name Description Example

property

Returns the given property in the returned results

property("firstName")

distinct

Returns results using a single or collection of distinct property names

distinct("fn") or distinct(['fn', 'ln'])

avg

Returns the average value of the given property

avg("age")

count

Returns the count of the given property name

count("branch")

countDistinct

Returns the count of the given property name for distinct rows

countDistinct("branch")

groupProperty

Groups the results by the given property

groupProperty("lastName")

max

Returns the maximum value of the given property

max("age")

min

Returns the minimum value of the given property

min("age")

sum

Returns the sum of the given property

sum("balance")

rowCount

Returns count of the number of rows returned

rowCount()

delete

delete

Purpose

Deletes a persistent instance.

Examples

def book = Book.get(1)
book.delete()

Description

The delete method informs the persistence context that a persistent instance should be deleted. Equivalent to the Hibernate delete method.

Calling delete on a transient instance will result in an error

Parameters:

  • flush - If set to true the persistent context will be flushed resulting in the instance being deleted immediately. For example:

def book = Book.get(1)
book.delete(flush: true)

discard

discard

Purpose

Discards any changes that have been made to a persistent instance.

Examples

def b = Book.get(1)
b.title = "Blah"
b.discard() // changes won't be applied now

Description

The discard method informs the persistence context that the instance should not be saved. The discard method is equivalent to using Hibernate’s evict method.

Note that this method will not clean or reset the object with the original values; it will just prevent it from being automatically saved by Grails.

embedded

embedded

Purpose

Supports embedding domain components into domain classes - otherwise known as composition.

Examples

Given these domain classes:

class Person {

    String name
    Country bornInCountry
    Country livesInCountry

    static embedded = ['bornInCountry', 'livesInCountry']
}

// If you don't want an associated table created for this class, either
// define it in the same file as Person or put Country.groovy under the
// src/main/groovy directory.
class Country {
    String iso3
    String name
}

Grails will generate a person database table that looks like:

Column Type

NAME

VARCHAR(255)

BORN_IN_COUNTRY_ISO3

VARCHAR(255)

BORN_IN_COUNTRY_NAME

VARCHAR(255)

LIVES_IN_COUNTRY_ISO3

VARCHAR(255)

LIVES_IN_COUNTRY_NAME

VARCHAR(255)

Description

An embedded component does not store its data in its own table as a regular domain class relationship does. Instead, the data is included in the owner’s table. So in the above example, the Country fields appear in the person table. This means that queries are faster because there is no join required, but you may end up with duplicate data across tables.

The embedded component class is typically declared in the same source file as the owning class or in its own file under src/main/groovy. You can put the component class under grails-app/domain, but if you do so Grails will automatically create a dedicated table for it. Putting the class under src/main/groovy is usually the best option because you can then share the component across multiple domain classes.

Querying on embedded properties is no different from querying on regular relationships, so you can for example still do:

Person.findAllByBornInCountry(brazil)
Person.findAllByLivesInCountry(france)

where brazil and france are instances of Country.

errors

errors

Purpose

An instance of the Spring {springapi}org/springframework/validation/Errors.html[Errors] interface containing data binding and/or validation errors.

Examples

def user = new User(params)

if (user.validate()) {
    // do something with user
}
else {
    user.errors.allErrors.each {
        println it
    }
}

Description

The errors property is used by Grails during data binding to store type conversion errors and during validation when calling the validate or save methods.

You can also add your own errors using the {springapi}org/springframework/validation/Errors#reject(java/lang/String).html[reject] and {springapi}org/springframework/validation/Errors#rejectValue(java/lang/String,%20java/lang/String).html[rejectValue] methods:

if (params.password != params.confirm_password) {

    user.errors.reject(
        'user.password.doesnotmatch',
        ['password', 'class User'] as Object[],
        '[Property [{0}] of class [{1}] does not match confirmation]')

    // The following helps with field highlighting in your view
    user.errors.rejectValue(
        'password',
        'user.password.doesnotmatch')

    render(view: 'signup', model: [user: user])
}

In the example of reject above, 'user.password.doesnotmatch', is the error code corresponding to a value in grails-app/i18n/message.properties, \['password', 'class User'\] as Object\[\] is a Groovy cast from a List to an Object array to match the expected signature, and '\[Property \[{0}\] of class \[{1}\] does not match confirmation\]' is the default mapping string.

In the rejectValue example, 'password' is the field in the view to highlight using a <g:hasErrors> tag and 'user.password.doesnotmatch' is the i18n error code.

executeQuery

executeQuery

Purpose

Executes HQL queries

Examples

// simple query
Account.executeQuery("select distinct a.number from Account a")

// using with list of parameters
Account.executeQuery("select distinct a.number from Account a " +
                     "where a.branch = ? and a.created > ?",
                     ['London', lastMonth])

// using with a single parameter and pagination params
Account.executeQuery("select distinct a.number from Account a " +
                     "where a.branch = ?", ['London'],
                     [max: 10, offset: 5])

// using with Map of named parameters
Account.executeQuery("select distinct a.number from Account a " +
                     "where a.branch = :branch",
                     [branch: 'London'])

// using with Map of named parameters and pagination params
Account.executeQuery("select distinct a.number from Account a " +
                     "where a.branch = :branch",
                     [branch: 'London', max: 10, offset: 5])

// same as previous
Account.executeQuery("select distinct a.number from Account a " +
                     "where a.branch = :branch",
                     [branch: 'London'], [max: 10, offset: 5])

// tell underlying Hibernate Query object to not attach newly retrieved
// objects to the session, will only save with explicit `save`
Account.executeQuery("select distinct a.number from Account a",
                     null, [readOnly: true])

// time request out after 18 seconds
Account.executeQuery("select distinct a.number from Account a",
                     null, [timeout: 18])

// have Hibernate Query object return 30 rows at a time
Account.executeQuery("select distinct a.number from Account a",
                     null, [fetchSize: 30])

// modify the FlushMode of the Query (default is `FlushMode.AUTO`)
Account.executeQuery("select distinct a.number from Account a",
                     null, [flushMode: FlushMode.MANUAL])

Description

The executeQuery method allows the execution of arbitrary HQL queries. HQL queries can return domain class instances, or `Array`s of specified data when the query selects individual fields or calculated values. The basic syntax is:

Book.executeQuery(String query)
Book.executeQuery(String query, List positionalParams)
Book.executeQuery(String query, List positionalParams, Map metaParams)
Book.executeQuery(String query, Map namedParams)
Book.executeQuery(String query, Map namedParams, Map metaParams)

Parameters:

  • query - An HQL query

  • positionalParams - A List of parameters for a positional parameterized query

  • namedParams - A Map of named parameters for a named parameterized query

  • metaParams - A Map of pagination parameters max or/and offset, as well as Hibernate query parameters readOnly, fetchSize, timeout, and flushMode

executeUpdate

executeUpdate

Purpose

Updates the database with DML-style operations

Examples

Account.executeUpdate("delete Book b where b.pages > 100")

Account.executeUpdate("delete Book b where b.title like ?",
                      ['Groovy In Action'])

Account.executeUpdate("delete Book b where b.author=?",
                      [Author.load(1)])

Account.executeUpdate("update Book b set b.title='Groovy In Action'" +
                      "where b.title='GINA'")

Account.executeUpdate("update Book b set b.title=:newTitle " +
                      "where b.title=:oldTitle",
                      [newTitle: 'Groovy In Action', oldTitle: 'GINA'])

Description

GORM does not provide a deleteAll method as deleting data must be done with caution. To delete data you can use executeUpdate. The basic syntax is:

Book.executeUpdate(String query)
Book.executeUpdate(String query, List positionalParams)
Book.executeUpdate(String query, Map namedParams)

Parameters:

  • query - An HQL query with DML-style operations

  • positionalParams - A List of parameters for a positional parameterized HQL query

  • namedParams - A Map of parameters for a named parameterized HQL query

exists

exists

Purpose

Checks whether an instance exists for the specified id

Examples

def accountId = ...
if (Account.exists(accountId)) {
    // do something
}

Description

Parameters:

  • id - The id of the object

fetchMode

fetchMode

Purpose

Allows the configuration of an associations fetch strategy (eager or lazy)

Examples

class Author {

    String name

    static hasMany = [books: Book]

    static fetchMode = [books: 'eager']
}

In this example the fetchMode static property specifies that the book association should be fetching eagerly

Description

By default associations in Grails are fetched lazily (each record is read from the database only when it is first accessed from the collection). This makes sense for most cases, however in the case where you have a small number of records to fetch and/or are repeatedly required to load lazy associations (resulting in N+1 queries) it makes sense to use eager fetching.

In the case of eager fetching and a one-to-many association, the instance as well as the association will be initialized when they are loaded (eagerly). However, caution should be observed when using eager fetching, since being too eager can result in your entire database being loaded into memory!

find

find

Purpose

Finds the first matching result for the given query or null if no instance is found

Examples

// Dan brown's first book
Book.find("from Book as b where b.author='Dan Brown'")

// with a positional parameter
Book.find("from Book as b where b.author=?", ['Dan Brown'])

// with a named parameter
Book.find("from Book as b where b.author=:author", [author: 'Dan Brown'])

// use the query cache
Book.find("from Book as b where b.author='Dan Brown'", [cache: true])
Book.find("from Book as b where b.author=:author",
          [author: 'Dan Brown'],
          [cache: true])

// query by example
def example = new Book(author: "Dan Brown")
Book.find(example)

// Using where criteria (since Grails 2.0)
Person p = Person.find { firstName == "Bart" }

Description

The find method allows querying with Hibernate’s query language HQL and querying by example. The basic syntax is:

Book.find(String query)
Book.find(String query, Collection positionalParams)
Book.find(String query, Collection positionalParams, Map queryParams)
Book.find(String query, Map namedParams)
Book.find(String query, Map namedParams, Map queryParams)
Book.find(Book example)
Book.find(Closure whereCriteria)

Parameters:

  • query - An HQL query

  • positionalParams - A List of parameters for a positional parametrized HQL query

  • namedParams - A Map of named parameters a HQL query

  • queryParams - A Map of query parameters. Currently, only cache is supported

  • example - An instance of the domain class for query by example

findAll

findAll

Purpose

Finds all of domain class instances matching the specified query

Examples

// everything
Book.findAll()

// with a positional parameter
Book.findAll("from Book as b where b.author=?", ['Dan Brown'])

// 10 books from Dan Brown staring from 5th book ordered by release date
Book.findAll("from Book as b where b.author=? order by b.releaseDate",
             ['Dan Brown'], [max: 10, offset: 5])

// examples with max/offset usage
def query = "from Book as b where b.author='Dan Brown' order by b.releaseDate"

// first 10 books
Book.findAll(query, [max: 10])

// 10 books starting from 5th
Book.findAll(query, [max: 10, offset: 5])

// examples with named parameters
Book.findAll("from Book as b where b.author=:author",
             [author: 'Dan Brown'])
Book.findAll("from Book as b where b.author=:author",
             [author: 'Dan Brown'], [max: 10, offset: 5])
Book.findAll("from Book as b where b.author in (:authors)",
             [authors: ['Dan Brown', 'Jack London']])

// examples with tables join
Book.findAll("from Book as b where not exists " +
                "(from Borrow as br where br.book = b)")

// query by example
def example = new Book(author: "Dan Brown")
Book.findAll(example)

// Use where criteria (since Grails 2.0)
def results = Person.findAll {
     lastName == "Simpson"
}
def results = Person.findAll(sort:"firstName") {
     lastName == "Simpson"
}

Description

The findAll method allows querying with Hibernate’s query language HQL and querying by example, returning all matching instances. Pagination can be controlled using the max and offset parameters:

Book.findAll("from Book as b where b.author=:author",
             [author: 'Dan Brown'], [max: 10, offset: 5])

The findAll method supports the 2nd level cache:

Book.findAll("from Book as b where b.author=:author",
             [author:'Dan Brown'], [max: 10, offset: 5, cache: true])

The basic syntax for the method is:

Book.findAll()
Book.findAll(String query)
Book.findAll(String query, Collection positionalParams)
Book.findAll(String query, Collection positionalParams, Map queryParams)
Book.findAll(String query, Map namedParams)
Book.findAll(String query, Map namedParams, Map queryParams)
Book.findAll(Book example)
Book.findAll(Closure whereCriteria)
Book.findAll(Map queryParams, Closure whereCriteria)
If you have a join in your HQL, the method will return a List of `Array`s containing domain class instances. You may wish to use executeQuery in this case so you have more flexibility in specifying what gets returned.

Parameters:

  • query - An HQL query

  • positionalParams - A List of parameters for a positional parametrized HQL query

  • namedParams - A Map of named parameters a HQL query

  • queryParams - A Map containing parameters max, and/or offset and/or cache

  • example - An instance of the domain class for query by example

  • readOnly - true if returned objects should not be automatically dirty-checked (simlar to read())

  • fetchSize - number of rows fetched by the underlying JDBC driver per round trip

  • flushMode - Hibernate FlushMode override, defaults to FlushMode.AUTO

  • timeout - query timeout in seconds

findAllBy

findAllBy*

Purpose

Dynamic method that uses the properties of the domain class to create query method expressions that return all matching instances of the domain class

Examples

Given this domain class:

class Book {
    String title
    Date releaseDate
    String author
    Boolean paperback
}

The following are all possible:

def results = Book.findAllByTitle("The Shining",
                  [max: 10, sort: "title", order: "desc", offset: 100])

results = Book.findAllByTitleAndAuthor("The Sum of All Fears", "Tom Clancy")

results = Book.findAllByReleaseDateBetween(firstDate, new Date())

results = Book.findAllByReleaseDateGreaterThanEquals(firstDate)

results = Book.findAllByTitleLike("%Hobbit%")

results = Book.findAllByTitleIlike("%Hobbit%") // ignore case

results = Book.findAllByTitleNotEqual("Harry Potter")

results = Book.findAllByReleaseDateIsNull()

results = Book.findAllByReleaseDateIsNotNull()

results = Book.findAllPaperbackByAuthor("Douglas Adams")

results = Book.findAllNotPaperbackByAuthor("Douglas Adams")

results = Book.findAllByAuthorInList(["Douglas Adams", "Hunter S. Thompson"])

Description

GORM supports the notion of Dynamic Finders. The findAllBy* method finds all the results for the given method expression.

Parameters:

  • metaParams - A M`ap containing pagination parameters `max, order, offset and sort and metaParameters readOnly, timeout, fetchSize, and flushMode

Pagination and sorting parameters can be used as the last argument to a dynamic method:

def results = Book.findAllByTitle("The Shining",
                 [max: 10, sort: "title", order: "desc", offset: 100])

If no items meet the supplied criteria an empty list is returned.

The following operator names can be used within the respective dynamic methods:

  • LessThan

  • LessThanEquals

  • GreaterThan

  • GreaterThanEquals

  • Between

  • Like

  • Ilike (i.e. ignorecase like)

  • IsNotNull

  • IsNull

  • Not

  • NotEqual

  • And

  • Or

  • InList

These operator names can be considered keywords, and you will run into problems when querying domain classes that have one of these names as property names. For more information on dynamic finders refer to the user guide.

findAllWhere

findAllWhere

Purpose

Uses named arguments corresponding to property names of the domain class to execute a query returning all matching results.

Examples

Given the domain class:

class Book {

   String title
   Date releaseDate
   String author

   static constraints = {
      releaseDate nullable: true
   }
}

You can query in the form:

def books = Book.findAllWhere(author: "Stephen King", title: "The Stand")

def unreleasedBooks = Book.findAllWhere(releaseDate: null)

Description

Parameters:

  • queryParams - A Map of key/value pairs to be used in the query

findBy

findBy*

Purpose

Dynamic method that uses the properties of the domain class to execute a query returning the first matching result.

Examples

Given the domain class Book:

class Book {
    String title
    Date releaseDate
    String author
    Boolean paperback
}

The following are all possible:

def b = Book.findByTitle("The Shining")
b = Book.findByTitleAndAuthor("The Sum of All Fears", "Tom Clancy")
b = Book.findByReleaseDateBetween(firstDate, new Date())
b = Book.findByReleaseDateGreaterThanEquals(firstDate)
b = Book.findByReleaseDateLessThanEquals(firstDate)
b = Book.findByTitleLike("%Hobbit%")
b = Book.findByTitleIlike("%Hobbit%") // ignores case
b = Book.findByTitleNotEqual("Harry Potter")
b = Book.findByReleaseDateIsNull()
b = Book.findByReleaseDateIsNotNull()
b = Book.findPaperbackByAuthor("Douglas Adams")
b = Book.findNotPaperbackByAuthor("Douglas Adams")
b = Book.findByAuthorInList(["Douglas Adams", "Hunter S. Thompson"])

Description

GORM supports the notion of Dynamic Finders. The findBy* method finds the first result for the given method expression.

The following operator names can be used within the respective dynamic methods:

  • LessThan

  • LessThanEquals

  • GreaterThan

  • GreaterThanEquals

  • Between

  • Like

  • Ilike (i.e. ignorecase like)

  • IsNotNull

  • IsNull

  • Not

  • NotEqual

  • And

  • Or

  • InList

The above operator names can be considered keywords, and you will run into problems when querying domain classes that have one of these names used as property names. For more information on dynamic finders refer to the user guide.

findOrCreateBy

findOrCreateBy*

Purpose

Dynamic method that uses the properties of the domain class to create query method expressions that return the first result of the query. This method behaves like findBy except that it will never return null. If a matching instance cannot be found then a new instance will be created and returned, populated with values represented in the query parameters. The difference between this method and findOrSaveBy is that this method will not save a newly created instance where findOrSaveBy does.

Examples

Given the domain class Book:

class Book {
   String title
   String author
}

The following are all possible:

def b = Book.findOrCreateByTitle("The Shining")
b = Book.findOrCreateByTitleAndAuthor("The Sum of All Fears", "Tom Clancy")
b = Book.findByAuthorInList(["Douglas Adams", "Hunter S. Thompson"])

The following are roughly equivalent:

def b = Book.findOrCreateByTitle("The Shining")
def b = Book.findByTitle("The Shining")
if (!b) {
    b = new Book(title: "The Shining")
}

Description

GORM supports the notion of Dynamic Finders. The findOrCreateBy* method finds the first result for the given method expression.

Because this method potentially creates a new instance and populates properties on that instance, only exact match criteria are allowed. For example, Book.findOrCreateByDate(dateValue) is valid but Book.findOrCreateByDateGreaterThan(dateValue) is not.

findOrCreateWhere

findOrCreateWhere

Purpose

Uses named arguments that match the property names of the domain class to produce a query that returns the first result. This method behaves just like findWhere except that it will never return null. If a matching instance cannot be found then a new instance will be created, populated with values from the query parameters and returned. The difference between this method and findOrSaveWhere is that this method will not save a newly created instance where findOrSaveWhere does.

Examples

Given the domain class:

class Book {

   String title
   Date releaseDate
   String author

   static constraints = {
      releaseDate nullable: true
   }
}

You can query in the form:

def book = Book.findOrCreateWhere(author: "Stephen King", title: "The Stand")

Description

Parameters:

  • queryParams - A Map of key/value pairs to be used in the query. If no matching instance is found then this data is used to initialize a new instance.

findOrSaveBy

findOrSaveBy*

Purpose

Dynamic method that uses the properties of the domain class to create query method expressions that return the first result of the query. This method behaves like findBy except that it will never return null. If a matching instance cannot be found then a new instance will be created, populated with values represented in the query parameters, saved and returned. The difference between this method and findOrCreateBy is that this method will save any newly created instance where findOrCreateBy does not.

Examples

Given the domain class Book:

class Book {
   String title
   String author
}

The following are all possible:

def b = Book.findOrSaveByTitleAndAuthor("The Sum of All Fears", "Tom Clancy")

The following are roughly equivalent:

def b = Book.findOrSaveByTitleAndAuthor("The Sum of All Fears", "Tom Clancy")
def b = Book.findByTitleAndAuthor("The Sum of All Fears", "Tom Clancy")
if (!b) {
    b = new Book(title: "The Sum of All Fears", author: "Tom Clancy")
    b.save()
}

Description

GORM supports the notion of Dynamic Finders. The findOrSaveBy* method finds the first result for the given method expression.

Because this method potentially creates a new instance and populates properties on that instance, only exact match criteria are allowed. For example, Book.findOrSaveByTitle(authorValue) is valid but Book.findOrSaveByAuthorInList(listOfNames) is not.

findOrSaveWhere

findOrSaveWhere

Purpose

Uses named arguments corresponding to property names of the domain class to execute a query returning the first matching result. This method behaves just like findWhere except that it will never return null. If a matching instance cannot be found in the database then a new instance is created, populated with values from the query parameters, saved and returned. The difference between this method and findOrCreateWhere is that this method will save a newly created instance where findOrCreateWhere does not.

Examples

Given the domain class:

class Book {

   String title
   Date releaseDate
   String author

   static constraints = {
      releaseDate nullable: true
   }
}

You can query in the form:

def book = Book.findOrSaveWhere(author: "Stephen King", title: "The Stand")

Description

Parameters:

  • queryParams - A Map of key/value pairs to be used in the query. If no matching instance is found then this data is used to initialize a new instance.

findWhere

findWhere

Purpose

Uses named arguments corresponding to domain class property names to execute a query returning the first matching result.

Examples

Given the domain class:

class Book {

   String title
   Date releaseDate
   String author

   static constraints = {
      releaseDate nullable: true
   }
}

You can query in the form:

def book = Book.findWhere(author: "Stephen King", title: "The Stand")

boolean isReleased = Book.findWhere(author: "Stephen King",
                                    title: "The Stand",
                                    releaseDate: null) != null

Description

Parameters:

  • queryParams - A Map of key/value pairs to be used in the query

first

first

Purpose

Retrieves the first instance of the domain class.

Examples

Given the domain class:

class Person {
    String firstName
    String lastName
    Integer age
}
// retrieve the first person ordered by the identifier
def p = Person.first()

// retrieve the first person ordered by the lastName property
p = Person.first(sort: 'lastName')

// retrieve the first person ordered by the lastName property
p = Person.first('lastName')

Parameters:

  • sort (optional) - The name of the property to sort by

See also:

Note that the first() and last() methods are not supported on domain classes which use a composite primary key.

get

get

Purpose

Retrieves an instance of the domain class for the specified id. null is returned if the row with the specified id doesn’t exist.

Examples

def b = Book.get(1)

Description

Parameters:

  • id - The id of the object to retrieve

getAll

getAll

Purpose

Retrieves a List of instances of the domain class for the specified ids, ordered by the original ids list. If some of the provided ids are null or there are no instances with these ids, the resulting List will have null values in those positions.

Examples

// get a list which contains Book instances with ids 2, 1, 3 respectively
def bookList = Book.getAll(2, 1, 3)

// can take a list of ids as only argument, very
// useful when the ids list is calculated in code
def bookList = Book.getAll([1, 2, 3])

// when called without arguments returns list of all objects
def bookList = Book.getAll()

Description

Parameters:

  • varargs* - A variable argument list of ids

  • ids* - A list of ids

getDirtyPropertyNames

getDirtyPropertyNames

Purpose

Retrieve the names of modified fields in a domain class instance.

Examples

def b = Book.get(1)
someMethodThatMightModifyTheInstance(b)

def names = b.dirtyPropertyNames
for (name in names) {
    def originalValue = b.getPersistentValue(name)
    ...
}

Description

This method is useful mostly for audit logging or other work done in a beforeUpdate event callback. Hibernate caches the original state of all loaded instances for dirty checking during a flush and this method exposes the names of modified fields so you can compare them with the current state.

getPersistentValue

getPersistentValue

Purpose

Retrieve the original value of a field for a domain class instance.

Examples

def b = Book.get(1)
someMethodThatMightModifyTheInstance(b)

if (b.isDirty('name')) {
    def currentName = b.name
    def originalName = b.getPersistentValue('name')
    if (currentName != originalName) {
        ...
    }
}

Description

This method is useful mostly for audit logging or other work done in a beforeUpdate event callback. Hibernate caches the original state of all loaded instances for dirty checking during a flush and this method exposes that data so you can compare it with the current state.

hasErrors

hasErrors

Purpose

Check if a domain class instance has validation errors following a call to validate or save, or following data binding

Examples

def b = new Book(title: "The Shining")
b.validate()
if (b.hasErrors()) {
    b.errors.allErrors.each {
        println it
    }
}

hasMany

hasMany

Purpose

Defines a one-to-many association between two classes.

Examples

class Author {

    String name

    static hasMany = [books: Book]
}

In this example we define a one-to-many relationship between the Author and Book classes (one Author has many `Book`s)

Description

By default GORM will create a property of type java.util.Set using the key inside the definition of the hasMany map. For example consider this definition:

static hasMany = [books: Book]

Here a property of type java.util.Set called books will be created within the defining class. These can then be iterated over and manipulated:

def a = Author.get(1)
for (book in a.books) { println book.title }

hasOne

hasOne

Purpose

Defines a bidirectional one-to-one association between two classes where the foreign key is in the child.

Examples

class Face {
    ..
    static hasOne = [nose: Nose]
}
class Nose {
    Face face
}

In this example we define a one-to-one relationship between the Face class and the Nose class

Description

Use a hasOne association to store the foreign key reference in child table instead of the parent in a bidirectional one-to-one. The example presented above will generate the following table structure:

create table face (id bigint generated by default as identity (start with 1),
                   version bigint not null,
                   primary key (id))
create table nose (id bigint generated by default as identity (start with 1),
                   version bigint not null,
                   face_id bigint not null,
                   primary key (id))

Notice that the foreign key face_id is stored in the nose table instead of the face table as with a normal one-to-one definition without belongsTo.

ident

ident

Purpose

Returns the value of the identity property of the domain class regardless of the name of the identity property itself

Examples

def b = new Book(title: "The Shining")
b.save()

println b.ident()

instanceOf

instanceOf

Purpose

Determines if a domain class instance is an instance of the specified class, resolving the actual class if the instance is a proxy.

Examples

Given the domain classes:

class Container {
   static hasMany = [children: Child]
}
class Child {
   String name
   static belongsTo = [container: Container]
}
class Thing extends Child {}
class Other extends Child {}

Then you can determine the type of the elements in a Container's children collection using

def container = Container.get(id)
for (child in container.children) {
   if (child.instanceOf(Thing)) {
      // process Thing
   }
   else if (child.instanceOf(Other)) {
      // process Other
   }
   else {
      // handle unexpected type
   }
}

Description

Parameters:

  • clazz - the type to check

isAttached

isAttached

Purpose

Returns whether the domain instance is attached to a currently active Hibernate session. This method is often used on conjunction with the merge or attach methods.

Examples

Book b = session.book
...
if (!b.isAttached()) {
    b.attach()
}

Description

Persistent instances are associated with a persistence Session. A new Session is created for each request and is closed at the end of the request. If an object is read from the session and placed into a web scope such as the HttpSession it is seen as detached, since the persistence session has been closed. You can use the attach method to re-attach an existing persistent instance to the persistence session of the current request.

isDirty

isDirty

Purpose

Checks to see if a domain class instance has been modified.

Examples

def b = Book.get(1)
someMethodThatMightModifyTheInstance(b)

// when called without arguments returns true if any field was changed
if (b.isDirty()) {
    // can also check if one field has changed
    if (b.isDirty('title')) {
        ...
    }
}

Description

Parameters:

  • fieldName - The name of a field to check

last

last

Purpose

Retrieves the last instance of the domain class.

Examples

Given the domain class:

class Person {
    String firstName
    String lastName
    Integer age
}
// retrieve the last person ordered by the identifier
def p = Person.last()

// retrieve the last person ordered by the lastName property
p = Person.last(sort: 'lastName')

// retrieve the last person ordered by the lastName property
p = Person.last('lastName')

Parameters:

  • sort (optional) - The name of the property to sort by

See also:

Note that the first() and last() methods are not supported on domain classes which use a composite primary key.

list

list

Purpose

Lists instances of the domain class.

Examples

// list everything
def results = Book.list()

// list 10 results
def results = Book.list(max: 10)

// list 10 results, offset by 100
def results = Book.list(max: 10, offset: 100)

// list 10 results, offset by 100, orderd by title in descending order
def results = Book.list(max: 10, offset: 100, sort: "title", order: "desc")

// list all books, eagerly fetching the authors association
def results = Book.list(fetch: [authors: "eager"])

When max is specified as a named argument this will return a PagedResultList which has a getTotalCount() method to return the total number of matching records for pagination. Two queries are still run, but they’re run for you and the results and total count are combined in the PagedResultList.

Description

Parameters:

  • max - The maximum number to list

  • offset - The offset from the first result to list from

  • order - How to order the list, either "desc" or "asc"

  • sort - The property name to sort by

  • ignoreCase - Whether to ignore the case when sorting. Default is true.

  • fetch - The fetch policy for the object’s associations as a Map

  • readOnly - true if returned objects should not be automatically dirty-checked (simlar to read())

  • fetchSize - number of rows fetched by the underlying JDBC driver per round trip

  • flushMode - Hibernate FlushMode override, defaults to FlushMode.AUTO

  • timeout - query timeout in seconds

listOrderBy

listOrderBy*

Purpose

Lists all of the instances of the domain class ordered by the property in the method expression

Examples

// everything
def results = Book.listOrderByAuthor()

// 10 results
def results = Book.listOrderByTitle(max: 10)

// 10 results, offset from 100
def results = Book.listOrderByTitle(max: 10, offset: 100, order: "desc")

Description

Parameters:

  • max - The maximum number to list

  • offset - The offset from the first result to list from

  • order - The order to list by, either "desc" or "asc"

load

load

Purpose

Returns a proxy instance of the domain class for the given identifier.

Examples

// load a single instance
def b = Book.load(1)
String title = b.title
...

// delete an instance without retrieving it
Book.load(1).delete()

Description

load usually returns a proxy for the instance which is initialized on-demand, when a method other than getId() is invoked. load() only returns null if the provided id is null, so you cannot use it to test for existence. If you provide an id for an instance that doesn’t exist, a proxy will be returned and an exception will be thrown only when you call any instance method other than getId().

If there is an existing instance with the same id in the Hibernate session or 2nd-level cache, load() will return that non-proxy instance instead of a proxy.

Parameters:

  • id - The id of the object to retrieve

lock

lock

Purpose

The lock method obtains a pessimistic lock using an SQL select ... for update.

Examples

def book = Book.get(1)
book.lock()

Description

The lock method obtains a pessimistic lock on an instance, locking the row in the database with select ... for update. The lock method is equivalent to using Hibernate’s LockMode.UPGRADE in combination with the http://docs.jboss.org/hibernate/orm/current/javadocs/org/hibernate/Session#lock(java/lang/Object, org/hibernate/LockMode).html[lock] method.

The lock is automatically released when the transaction commits. In Grails this is typically after an action has finished executing.

Refer to the section on Optimistic and Pessimistic locking in the user guide for info.

mappedBy

mappedBy

Purpose

The mappedBy static property allows you to control whether an association is mapped as unidirectional or bidirectional, and which properties form the reverse direction in the case of bidirectional associations.

Examples

In this example the Airport class defines two bidirectional one-to-many associations. Without defining mappedBy this is impossible as GORM cannot differentiate which of the two properties on the other end of the association (either departureAirport or destinationAirport in the Route class) each one-to-many should be associated with.

The solution is to define mappedBy which tells the Airport class how each association relates to the other side.

class Airport {

    static mappedBy = [outgoingFlights: 'departureAirport',
                       incomingFlights: 'destinationAirport']

    static hasMany = [outgoingFlights: Route,
                      incomingFlights: Route]
}
class Route {
    Airport departureAirport
    Airport destinationAirport
}

Separate example for many-to-one relationships:

class Person {
    String name
    Person parent

    static belongsTo = [ supervisor: Person ]

    static mappedBy = [ supervisor: "none", parent: "none" ]

    static constraints = { supervisor nullable: true }
}

Description

Grails needs to know whether associations are unidirectional or bidirectional, and in the case of the latter, which properties are involved from both sides. Normally it can infer this information, but when there are multiple properties with the same type its guess can sometimes be wrong. The mappedBy property is a simple map of property name pairs, where the key is the name of an association property in the current domain class and the value is the name of an association property in the domain class on the other side of the association (which may be itself). The examples above should clarify this.

You can also specify a value of "none" in the map, which indicates that the association is unidirectional. However, this won’t work if you actually have a domain property called "none" in the target class!

mapping

mapping

Purpose

The mapping static property configures how GORM maps the domain class to the database. See the section on the ORM DSL in the user guide for more information.

Examples

class Person {

    String firstName

    static hasMany = [addresses: Address]

    static mapping = {
        table 'people'
        version false
        id column: 'person_id'
        firstName column: 'First_Name'
        addresses lazy: false
    }
}

This example uses the ORM DSL to map the Person class onto a table called people

mapWith

mapWith

Purpose

The mapWith static property adds the ability to control if a domain class is being persisted.

Examples

class Airport {

    static mapWith = "none"

}

In this example the Airport class will not be persisted to the database.

merge

merge

Purpose

Merges a domain class instance back into the current persistence context and returns a new merged instance.

Examples

def b = new Book(title: "The Shining")
b = b.merge()

Description

The merge method is similar in function to the save method, but not in behaviour. merge allows the merging of "detached" instances such as those stored in the HTTP session. Each persistent instance is associated with a persistence context. A new persistence context is created for each request. The result is that objects stored in the HTTP session lose their persistence context on subsequent requests. In this case you can’t simply call save as the domain class is not associated with a current context.

The merge method on the other hand lets you merge a detached object’s state back into the current Hibernate session. Unlike the save method this method returns a new instance of the class representing the re-attached object. In other words you must write code like this:

book = book.merge()

If you don’t use the return value of the merge method then you still have access to the original unmodified detached instance and you will get errors such as lazy initialization exceptions.

The merge method is defined in the Hibernate documentation as follows:

Copy the state of the given object onto the persistent object with the same identifier. If there is no persistent instance currently associated with the session, it will be loaded. If the given instance is unsaved, save a copy of and return it as a newly persistent instance.

The merge method is equivalent to the Hibernate merge method.

Parameters:

  • validate (optional) - Set to false if validation should be skipped

  • flush (optional) - When set to true flushes the persistence context, hence persisting the object immediately

namedQueries

namedQueries

Purpose

The namedQueries static property defines named queries. Named queries support the criteria builder syntax. See the section on the Criteria Builder in the user guide for more information.

Examples

class Publication {

   String title
   String author
   Date datePublished
   Integer numberOfPages

   static namedQueries = {
       recentPublications {
           def now = new Date()
           gt 'datePublished', now - 365
       }

       oldPublicationsLargerThan { pageCount ->
           def now = new Date()
           lt 'datePublished', now - 365
           gt 'numberOfPages', pageCount
       }

       publicationsWithBookInTitle {
           like 'title', '%Book%'
       }

       recentPublicationsWithBookInTitle {
           // calls to other named queries...
           recentPublications()
           publicationsWithBookInTitle()
      }
   }
}
// get all recent publications...
def recentPubs = Publication.recentPublications.list()

// get up to 10 recent publications, skip the first 5...
def recentPubs = Publication.recentPublications.list(max: 10, offset: 5)

// get a single recent publication
def recentPub = Publication.recentPublications.get()

// get the number of recent publications...
def numberOfRecentPubs = Publication.recentPublications.count()

// get a recent publication with a specific id...
def pub = Publication.recentPublications.get(42)

// get all recent publications where title = 'Some Title'
def pubs = Publication.recentPublications.findAllWhere(title: 'Some Title')

// get a recent publication where title = 'Some Title'
def pub = Publication.recentPublications.findWhere(title: 'Some Title')

// dynamic finders are supported
def pubs = Publication.recentPublications.findAllByTitle('Some Title')

// get all old publications with more than 350 pages
def pubs = Publication.oldPublicationsLargerThan(350).list()

// get all old publications with more than 350 pages
// and the word 'Grails' in the title
def pubs = Publication.oldPublicationsLargerThan(350).findAllByTitleLike('%Grails%')

// get all recent publications with 'Book' in their title
def pubs = Publication.recentPublicationsWithBookInTitle().list()

The list method on named queries supports the same attributes as the static list method added to domain classes (sort, order, ignoreCase, fetch etc…​). See the list docs for details.

Note that calling something like Publication.recentPublications.get(42) is not the same as calling something like Publication.get(42). The former will only return a Publication if the Publication with id 42 meets all the criteria defined in the recentPublications named query.

Named criteria support listDistinct():

class PlantCategory {

    Set plants
    String name

    static hasMany = [plants: Plant]

    static namedQueries = {
        withPlantsInPatch {
            plants {
                eq 'goesInPatch', true
            }
        }
    }
}
class Plant {
    boolean goesInPatch
    String name
}
PlantCategory.withPlantsInPatch.listDistinct()

Named criteria support additional criteria being supplied at invocation time in the form of a criteria closure:

// get all recent publications with author names beginning with Tony or Phil...
def books = Publication.recentPublications {
    or {
        like 'author', 'Tony%'
        like 'author', 'Phil%'
    }
}

// get the number of recent publications with
// author names beginning with Tony or Phil...
def numberOfBooks = Publication.recentPublications.count {
    or {
        like 'author', 'Tony%'
        like 'author', 'Phil%'
    }
}

Named criteria may be chained together. When criteria are chained together, the query will be generated as if all of the chained criteria had been combined in a single criteria closure.

// recent publications with 'Book' in the title
def books = Publication.recentPublications.publicationsWithBookInTitle.list()

// old publications with more than 500 pages and with 'Book' in the title
def books = Publication.oldPublicationsLargerThan(500)
                       .publicationsWithBookInTitle
                       .list()

When a named query involves a domain class relationship and the relationship class defines a named query, that named query may be accessed directly as a method call. An example:

class Author {

    static hasMany = [publications: Publication]

    static namedQueries = {
         authorsWithRecentPublications {
             publications {
                 // invoking a named query defined in the Publication class...
                 recentPublications()
             }
         }
    }
}
class Publication {

    Author author

    static namedQueries = {
        recentPublications {
            def now = new Date()
            gt 'datePublished', now - 10
        }
    }
}

properties

properties

Purpose

Allows access to the domain class properties as a Map and is typically used for data binding to perform type conversions allowing properties to be set from request parameters or other Maps.

Examples

def b = new Book(title: "The Shining")
b.properties = params
b.save()

read

read

Purpose

Retrieves an instance of the domain class for the specified id in a read-only state. null is returned if the row with the specified id doesn’t exist.

Examples

def b = Book.read(1)

Description

The read method is similar to the get method except that automatic dirty detection is disabled. The instance isn’t truly read-only - you can modify it - but if it isn’t explicitly saved but has been modified, it won’t be updated in the database during a flush. But you can explicitly call save() and it will be updated. There is one exception to this though - any associated collections, for example an Author's books collection, will participate in automatic flushing and dirty detection. This is because mapped collections are treated differently than regular properties and they manage their own dirty checking indepenent of the containing domain class.

Parameters:

  • id - The id of the object to retrieve

refresh

refresh

Purpose

Refreshes a domain classes state from the database

Examples

def b = Book.get(1)
...
b.refresh()

Description

Equivalent to the Hibernate refresh method.

Re-reads the state of the given instance from the underlying database. It is inadvisable to use this to implement long-running sessions that span many business tasks. However this method is useful in certain special circumstances. For example

  • where a database trigger alters the object state upon insert or update

  • after executing direct SQL (e.g. a bulk update) in the same Session

  • after inserting a Blob or Clob

removeFrom

removeFrom*

Purpose

Opposite of the addTo method in that it removes instances from an association.

Examples

def author = Author.findByName("Stephen King")

def book = author.books.find { it.title == 'The Stand' }

author.removeFromBooks(book)

save

save

Purpose

Saves a new domain class instance or updates a modified persistent instance in the database, cascading updates to child instances if required.

Examples

def b = new Book(title: "The Shining")
b.save()

Description

The save method informs the persistence context that an instance should be saved or updated. The object will not be persisted immediately unless the flush argument is used:

b.save(flush: true)

The save method returns null if validation failed and the instance was not persisted, or the instance itself if successful. This lets you use "Groovy truth" (null is considered false) to write code like the following:

if (!b.save()) {
    b.errors.allErrors.each {
        println it
    }
}

Parameters:

  • validate (optional) - Set to false if validation should be skipped

  • flush (optional) - When set to true flushes the persistence context, persisting the object immediately and updating the version column for optimistic locking

  • insert (optional) - When set to true will force Hibernate to do a SQL INSERT; this is useful in certain situations (for example when using assigned ids) and Hibernate cannot detect whether to do an INSERT or an UPDATE

  • failOnError (optional) - When set to true the save method with throw a grails.validation.ValidationException if validation fails. This behavior may also be triggered by setting the grails.gorm.failOnError property in grails-app/conf/application.groovy. If the Config property is set and the argument is passed to the method, the method argument will always take precedence. For more details about the config property and other GORM config options, see the GORM Configuration Options section of The User Guide.

  • deepValidate (optional) - Determines whether associations of the domain instance should also be validated, i.e. whether validation cascades. This is true by default - set to false to disable cascading validation.

By default GORM classes are configured for optimistic locking, which is a feature of Hibernate that involves storing an incrementing version in the table. This value is only updated in the database when the Hibernate session is flushed.

transients

transients

Purpose

Defines a list of property names that should not be persisted to the database. This is often useful if you have read-only accessor methods ("getters") that are helper methods but get confused as being persistence-related.

Examples

class Author {
   String name
   String getUpperCaseName() { name.toUpperCase() }

   static transients = ['upperCaseName']
}

Here we have an accessor that takes the name and converts it to uppercase. It doesn’t make sense to persist this derived value, so we mark it as transient adding its JavaBean property name to the transients list.

As of Grails 2.0 if there is only a getter or only a setter method, you don’t need to declare the property name of the method in the transients list. Only typed fields and get/set pairs that form a property but shouldn’t be persisted need to go in the transients list.

validate

validate

Purpose

Validates a domain class against the applied constraints (see validation)

Description

The validate method validates a domain class based on its defined Constraints. The errors are stored in the errors property of the domain class instance.

The validate method accepts an optional List argument which contains the names of the properties to be validated. When a List of names is specified, only those properties will be validated.

Examples

def b = new Book(title: "The Shining")
if (!b.validate()) {
    b.errors.allErrors.each {
        println it
    }
}
def a = new Album(artist: "Genesis", title: "Nursery Cryme", releaseDate: 1971)

// only validate title and releaseDate
if (!a.validate(["title", "releaseDate"])) {
    a.errors.allErrors.each {
        println it
    }
}

Parameters:

  • deepValidate (optional) - Whether associations of the domain instance should also be validated, i.e. whether validation cascades. This is true by default; set it to false to disable cascading validation.

where

where

Purpose

Defines a new grails.gorm.DetachedCriteria instance.

Examples

Basic query:

def query = Person.where {
   firstName == "Bart"
}
Person bart = query.find()

Conjunctions/Disjunctions:

def query = Person.where {
    (lastName != "Simpson" && firstName != "Fred") || (firstName == "Bart" && age > 9)
}
def results = query.list(sort:"firstName")

Property comparison:

def query = Person.where {
   firstName == lastName
}

Querying Associations:

def query = Pet.where {
    owner.firstName == "Joe" || owner.firstName == "Fred"
}

Subqueries:

final query = Person.where {
  age > avg(age)
}

Description

The where method is a powerful new type-safe querying option introduced in Grails 2.0. For more information on using the where method see the dedicated section on Where Queries and Detached Criteria in the user guide.

whereAny

where

Purpose

Defines a new grails.gorm.DetachedCriteria instance that uses a disjunction (logical OR).

Examples

Basic query:

def query = Person.whereAny {
   firstName == "Bart"
   firstName == "Lisa"
}
Person bart = query.find()

Description

The where method defaults to a conjunction (logical AND) for the created query. The whereAny compliments the where method by allowing the creation of DetachedCriteria using a disjunction (logical OR).

The where method is a powerful new type-safe querying option introduced in Grails 2.0. For more information on using the where method see the dedicated section on Where Queries and Detached Criteria in the user guide.

withCriteria

withCriteria

Purpose

Allows inline execution of Criteria queries. See the createCriteria method for reference.

Return value

If no matching records are found, an empty List is returned.

If a projection is specified:

  • returns a single value if it only contains one field

  • a List in case there are multiple fields in the projection

Otherwise, it will return a List of matched instances of the class calling withCriteria.

Examples

def results = Book.withCriteria {
    def now = new Date()
    between('releaseDate', now-7, now)
    like('title', '%Groovy%')
}

Description

The withCriteria method allows the inline definition of Criteria. Arguments to the [http://grails.github.io/grails-data-mapping/latest/api/grails/orm/HibernateCriteriaBuilder.html] can be passed as the first parameter:

def book = Book.withCriteria(uniqueResult: true) {
    def now = new Date()
    between('releaseDate', now-7, now)
    like('title', '%Groovy%')
}

Parameters:

  • arguments (optional) - A map of named arguments to be set on the Criteria instance

  • closure - A closure that defines the criteria

withNewSession

withNewSession

Purpose

Provides a way to execute code within the context of a new Hibernate session which shares the same transactional (JDBC Connection) resource as the currently bound session.

Examples

Book.withNewSession { session ->
    // do work
}

Description

Parameters:

  • closure - A closure which accepts a Session argument

withSession

withSession方法

目的

提供 Hibernate Session 对象的底层权限

示例

Book.withSession { session ->
    session.clear()
}

描述

参数:

  • closure - 接受 Session 参数的闭包

withTransaction

withTransaction方法

目的

允许编程式事务使用Spring的事务抽象。

示例

Account.withTransaction { status ->

    def source = Account.get(params.from)
    def dest = Account.get(params.to)

    int amount = params.amount.toInteger()
    if (source.active) {
        source.balance -= amount

        if (dest.active) {
            dest.amount += amount
        }
        else {
            status.setRollbackOnly()
        }
    }
}

命名参数可以根据需要作为参数传递,以控制事务的属性。

//Map的key必须与 org.springframework.transaction.support.DefaultTransactionDefinition 中的属性一致。

Account.withTransaction([propagationBehavior: TransactionDefinition.PROPAGATION_REQUIRES_NEW,
                         isolationLevel: TransactionDefinition.ISOLATION_REPEATABLE_READ]) {
    // ...
}

描述

withTransaction 方法接受一个含有 TransactionStatus 参数的闭包。

TransactionStatus 对象可以被用来以编程方式控制事务回滚。

详情请参见 Programmatic Transactions

Constraints

attributes

Unresolved directive in reference.adoc - include::ref/Constraints/attributes.adoc[]

bindable

Unresolved directive in reference.adoc - include::ref/Constraints/bindable.adoc[]

blank

blank 约束

目的

验证字符串值是否为空白字符串值''.

示例

login blank: false

描述

如果字符串值不能为空字符串值'',则设置为“false”.

错误代码 Code: className.propertyName.blank

注意:如果字符串为“null”,它将不能通过验证“blank: true”。在这种情况下,设置 nullable约束为`true`。

creditCard

creditCard约束

目的

验证字符串值是有效的信用卡号

示例

cardNumber creditCard: true

描述

如果字符串必须是信用卡号码,则设置为“true”。内部使用`org.apache.commons.validator.CreditCardValidator`类。

错误代码 Code: className.propertyName.creditCard.invalid

email

email约束

目的

验证字符串值是有效的电子邮件地址.

示例

homeEmail email: true

描述

如果字符串值必须是电子邮件地址,则设置为“true”。内部使用`org.apache.commons.validator.EmailValidator`类。

错误代码 Code: className.propertyName.email.invalid

inList

inList约束

目的

验证值是否在约束值的范围或集合中.

示例

name inList: ["Joe", "Fred", "Bob"]

描述

约束一个值,使其必须包含在给定的列表中.

这种约束的影响参见 schema generation.

错误代码 Code: className.propertyName.not.inList

matches

matches约束

目的

验证字符串值是否与给定的正则表达式匹配.

例子

login matches: "[a-zA-Z]+"

例子

对字符串值应用正则表达式.

错误代码 Code: className.propertyName.matches.invalid

max

max约束

目的

确保值不超过最大值.

示例

age max: new Date()
price max: 999F

描述

可以设置最大值为任意实现接口implements `java.lang.Comparable`的类对象.值的类型必须和属性的类型相同。

注意: 如果值为`java.util.Date`类型,约束的值只在评估执行时创建一次。

class User {
    ...

    static constraints = {
        //此日期对象在评估约束执行时创建,而不是每次验证用户类的实例时创建
        birthDate max: new Date()
    }
}

这种约束的影响参见 schema generation.

错误代码 Code: className.propertyName.max.exceeded

maxSize

maxSize约束

目的

确保值的大小不超过最大值.

示例

children maxSize: 25

描述

这种约束的影响参见 schema generation.

错误代码 Code: className.propertyName.maxSize.exceeded

min

min约束

目的

确保值不低于最小值

示例

age min: new Date()
price min: 0F

描述

可以设置最小值为任意实现接口implements `java.lang.Comparable`的类对象.值的类型必须和属性的类型相同。

注意: 如果值为`java.util.Date`类型,约束的值只在评估执行时创建一次。

class User {
    ...

    static constraints = {
        //此日期对象在评估约束执行时创建,而不是每次验证用户类的实例时创建
        age min: new Date()
    }
}

这种约束的影响参见 schema generation.

错误代码 Code: className.propertyName.min.notmet

minSize

minSize约束

目的

确保值的大小不低于最小值.

示例

children minSize: 25

描述

设置集合或数字属性的最小大小.

这种约束的影响参见 schema generation.

错误代码 Code: className.propertyName.minSize.notmet

notEqual

notEqual约束

目的

确保属性不等于指定值

示例

username notEqual: "Bob"

描述

错误代码 Code: className.propertyName.notEqual

nullable

nullable约束

目的

允许属性设置为“null”,默认设置为`false`

示例

age nullable: true

描述

如果属性允许设置为`null`值,设置为`true`.对应数据库会设置为allow null.

这种约束的影响参见 schema generation.

错误代码 Code: className.propertyName.nullable

注意:web请求表单提交,对于没有输入值的输入框, 属性的值为空白字符串,不是`null`.

range

range约束

目的

使用Groovy的Range类型以确保属性值在指定范围内

示例

age range: 18..65

描述

Groovy的Range类型可以包含数字类型`IntRange`或日期类型,或者任意类型(实现了implements Comparable ,并且提供`next` 和 previous 两个方法)

这种约束的影响参见 schema generation.

错误代码 Code: className.propertyName.range.toosmall 或者 className.propertyName.range.toobig

scale

scale约束

目的

设置为浮点数字所需的尺度(即小数点右边的位数)

示例

salary scale: 2

描述

设置为浮点数字所需的尺度(即小数点右边的位数)。这个限制适用于以下类型的属性: java.lang.Float, java.lang.Double, and java.math.BigDecimal (及其子类)。当验证被调用时,此约束确定该数字是否包含比刻度允许更多的非零小数位置。如果是这样,它将数字循环到由刻度允许的最大小数位数。此约束不会生成验证错误消息。

这种约束的影响参见 schema generation.

无错误代码 Code: N/A

size

size约束

目的

使用Groovy的Range类型限制集合、数字或字符串长度的大小

示例

children size: 5..15

描述

设置集合的大小、数字属性或字符串长度.

注意: 目前这个约束不能用于 blank 或者 nullable.可以使用自定义验证这些组合.

这种约束的影响参见 schema generation.

错误代码 Code: className.propertyName.size.toosmallclassName.propertyName.size.toobig

unique

unique约束

目的

在数据库级别将属性限制为唯一,会在数据库表上建立唯一性约束

示例

username unique: true

描述

如果属性必须是唯一的,则设置为`true`。这是一个持久的调用,将查询数据库。

警告:有可能会发生(虽然不可能在实践中出现)唯一性验证通过,但随后的保存失败。场景为:如果同时有其他的进程修改数据库在GORM检查的同时,那么相关调用将失败。为了防止这一点的唯一方法就是使用`SERIALIZABLE`隔离级别的事务,但对性能影响很大。 还可以通过定义将字段包含为参数值来定义多列的“唯一”约束。如果有另一个字段,请指定它的名称,但如果有多于一个字段,请使用列表List,例如:

示例:

group unique: 'department'

这个例子中,每个`department`部门内`group`名是唯一的,不同的部门可以存在重名的组。组名本身不是唯一的.

示例2:

username(unique: ['group', 'department'])

这个例子要求在一个部门和组内的 `username`用户名是唯一的。不同的部门或不同的组内可以存在重名的情况

这种约束的影响参见 schema generation.

错误代码 Code: className.propertyName.unique

url

url约束

Purpose

验证字符串值是有效URL.

例子

homePage url: true

描述

如果一个字符串是 URL设置为 true .

错误代码 Code: className.propertyName.url.invalid

validator

validator约束

目的

为字段添加自定义约束.

例子

even validator: {
    return (it % 2) == 0
}

// is equivalent to
even validator: { val ->
    return (val % 2) == 0
}

// 闭包的两个参数,第一个是属性值,第二个是实例对象
password1 validator: { val, obj ->
    obj.password2 == val
}

//闭包的三个参数,第一个是属性值,第二个是实例对象 ,第三个是errors错误对象
password1 validator: { val, obj, errors ->
    if (!(obj.password2 == val)) errors.rejectValue('password1', 'noMatch')
}

// Examples 传递参数到i18n的消息中 message.properties
// Example 1: 使用隐式的参数 0 (属性名称)

class Person {

    String name

    static constraints = {
        name validator: {
	  if (!it) return ['entryMissing']
       }
}

// 上述例子将调用如下消息:
// person.name.entryMissing=Please enter a name in the field {0}

// Example 2: 使用隐式的参数 0 (属性名称) and 参数2 (属性值)

class Person {

    Integer yearOfBirth

    static constraints = {
        yearOfBirth validator: {
	  if (yearOfBirth>2013) return ['yearTooBig']
       }
}

// 上述例子将调用如下消息:
// person.yearOfBirth.yearTooBig=The value {2} entered in the field {0} is not valid because it lies in the future.

// Example 3: 复杂

class Astronaut {

    Integer yearOfBirth
    Integer yearOfFirstSpaceTravel

        yearOfFirstSpaceTravel validator: { val, obj ->
                if (val < obj.yearOfBirth) ['datePriorTo', val.toString(), obj.yearOfBirth]
                else if (val < (obj.yearOfBirth+18)) ['maybeABitTooYoung', val-obj.yearOfBirth]
        }
}

// 各自的消息
// 注意,参数3是属性值转换toString方法,以避免不必要的格式,如前所述.
astronaut.yearOfFirstSpaceTravel.datePriorTo=The value {3} entered for the year of the first space travel is prior to the year of birth ({4}). Please correct the value.
astronaut.yearOfFirstSpaceTravel.maybeABitTooYoung={3} years seems a bit young for travelling to space, dude!

描述

自定义验证通过闭包来实现,并接受3个参数。 如果闭包接受0个或1个参数,参数值将被验证("it" 是闭包的第0个参数). 如果接受2个参数,第一个是值,第二个是domain类的实例. 如果接受3个参数,第一个是值,第二个是domain类的实例,第3个是Spring Errors 对象。

闭包可以返回:

  • null 或者 true (或者没有返回值) 说明值是有效的。

  • false 说明值是无效的并使用默认的消息代码

  • string 指明错误代码增加到 "classname.propertyName."字符串后,从而获取错误消息.如果无法解决特定字段消息,错误代码本身将使用全局错误消息.

  • 一个包含字符串的list列表,后面是参数. 将使用 i18n/message.properties 中的定义组织消息。 参数的映射如下:参数0到2将自动映射到0:属性名称,1:类名,2:属性值。在参数3开始映射附加参数。

请注意,在最后的错误信息,该属性的标签将使用在message.properties文件中的定义。否则,将使用类中定义的属性名称。

当显式传递的错误代码,通常不需要使用"return"关键词返回的错误代码,因为如果从闭包返回时,它将检查错误是否已连接到错误的对象。

这可以看作特例,闭包中传递了第3个参数,预计错误的对象`Errors`将直接更新。

widget

Unresolved directive in reference.adoc - include::ref/Constraints/widget.adoc[]

Database Mapping

autoImport

autoImport映射

目的

在当前domain类的 HQL 查询中 Enable/disable auto import .

示例

class Book {
    ...
    static mapping = {
        autoImport false
    }
}

描述

Usage: autoImport(boolean)

默认情况下,domain类在HQL查询是auto-imported,因此,您不需要指定整个类名(包括包),但是,如果在不同的包中有重复的domain类名,则名称不再是唯一的,会造成`org.hibernate.DuplicateMappingException`错误。禁用其中一个或两个domain类的自动导入来修复此错误,设置`autoImport` 为 false。记住,你需要在HQL的查询中使用完全的domain类名引用。

static mapping = {
    autoImport false
}

autoTimestamp

autoTimestamp映射

目的

设置为false时,关闭自动时间戳功能

示例

class Book {
    ...
    static mapping = {
        autoTimestamp false
    }
}

描述

Usage: autoTimestamp(boolean)

缺省当domain类中的属性名为 dateCreatedlastUpdated , GORM会在数据库自定维护这两个字段。可以通过设置为false关闭此功能:

static mapping = {
    autoTimestamp false
}

batchSize

batchSize映射

目的

定制多少结果获取在懒加载执行时.

示例

class Book {
    ...
    static mapping = {
        batchSize 10
    }
}

描述

Usage: batchSize(integer)

针对`Author` 类拥有多个 Book`实例的延迟加载关联。GORM将执行一条查询`Author`和附加查询多条关联`Book`实例。 这就是著名的N+1问题,通常使用表连接处理,然而,关联表会消耗性能。 批量加载是针对延迟加载的一个优化方案,例如设置`batchSize`为10,并且当前作者拥有30本书. 系统将执行四次获取(一次`Author,3次批量10对象的获取),替换之前的31此获取:

static mapping = {
    batchSize 10
}

也可以在关联端设置 batchSize :

class Author {

    static hasMany = [books: Book]

    static mapping = {
        books batchSize: 10
    }
}

cache

cache映射

目的

配置domain类支持Hibernate二级缓存.

示例

class Book {
    ...
    static mapping = {
        cache true
    }
}

示例

Usage: cache(boolean/string/map)

参数:

  • cache - 缓存使用. 可被设置为 read-only, read-write, nonstrict-read-writetransactional

  • include (optional) - 是否包含非延迟加载关联项。可被设置为 allnon-lazy

示例:

static mapping = {
    cache true
}

这将配置domain类使用’read-write' 缓存,需要提前确认配置的缓存政策被允许使用(缓存引擎提供支持):

static mapping = {
    cache 'transactional'
}

or

static mapping = {
    cache usage: 'read-only', include: 'non-lazy'
}

也可以在关联端设置缓存:

class Author {

    static hasMany = [books: Book]

    static mapping = {
        books cache: true // or 'read-write' etc.
    }
}

参照文档获取更多信息 Caching .

cascade

cascade映射

目的

配置关联项的级联操作

示例

class Author {

    static hasMany = [books: Book]

    static mapping = {
        books cascade: 'all-delete-orphan'
    }
}

描述

Usage: association_name(cascade:string)

参数:

  • cascade - 定义级联行为. 可被设置为一个或多个 (comma-separated逗号分隔) of all, merge, save-update, delete, lock, refresh, evict, replicate or all-delete-orphan (one-to-many只支持一对多关系).

默认GORM会配置"belongs to"属性对象的级联操作为"all",示例如下:

class Book {
    static belongsTo = [author: Author]
}
class Author {
    static hasMany = [books: Book]
}

所以的持久化操作都会从`Author` 类传递到 Book 类。作者对象删除将导致关联的图书全部删除。

如果关联没有设置所有者("belongs to" 关联关系):

class Book {
}
class Author {
    static hasMany = [books: Book]
}

GORM默认使用"save-update"级联策略. 作者对象删除时,不会级联删除关联的图书。 使用`cascade`参数自定义级联行为:

class Author {

    static hasMany = [books: Book]

    static mapping = {
        books cascade: 'all-delete-orphan'
    }
}

以上配置,`Book`当成为孤儿(orphaned) 时会被删除。.

参看文档获取更多信息 transitive persistence .

column

column映射

目的

自定义数据列的设置

示例

static mapping = {
        currency column: "currency", sqlType: "char", length: 3
    }

描述

Usage: property_name(map)

Arguments:

  • column - The name of the column as a String

  • sqlType (optional) - The underlying SQL type

  • enumType (optional) - The enum type in for type-safe Enum properties. Either ordinal or string.

  • index (optional) - The index name

  • unique (optional) - Whether it is unique

  • length (optional) - The length of the column

  • precision (optional) - The precision of the column

  • scale (optional) - The scale of the column

  • comment (optional) - The comment for the column (used to create the table DDL)

  • defaultValue (optional) - The database default value

By default GORM uses the property name and type to determine how to map a property in the database. For example a String property is typically mapped as a varchar(255) column. You can customize these with column configuration arguments:

static mapping = {
    currency column: "currency", sqlType: "char", length: 3
}

If you use a Hibernate type that requires multiple column definitions you can use the column method to define each column:

static mapping = {
    amount type: MonetaryUserType, {
        column name: "value"
        column name: "currency", sqlType: "char", length: 3
    }
}

Note that if you have a static method that is the same name as one of your properties you are trying to configure or you use the same property name as one of the static GORM methods this can lead to conflicts. To avoid this scenario scope the mapping configuration using the delegate property:

static mapping = {
    delegate.currency column: "currency", sqlType: "char", length: 3
}

comment

comment映射

目的

设置生成表创建sql(DDL)时使用的注释.

示例

class Book {
   static mapping = {
      comment "your comment here"
   }
}

描述

Usage: comment(string)

参数:

  • comment - 具体注释

discriminator

discriminator

Purpose

Customizes the discriminator column used in table-per-hierarchy inheritance mapping. Has no effect when using table-per-subclass inheritance mapping.

Examples

class Content {
    ...
}
class PodCast extends Content {
    ...
    static mapping = {
        discriminator "audio"
    }
}

Description

Usage: discriminator(string/map)

Arguments:

  • column (optional) - The column name to store the discriminator

  • value - The value to use for the discriminator

  • formula (optional) - an SQL expression that is executed to evaluate the type of class. Use this or column but not both

  • type (optional defaults to string) - the Hibernate type, used for the where clause condition to know if it needs to wrap it with '

By default when mapping inheritance Grails uses a single-table model where all classes share the same table. A discriminator column is used to determine the type for each row, by default the full class name. You can use the discriminator method to customize what’s stored:

class Content {
    ...
}
class PodCast extends Content {
    ...
    static mapping = {
        discriminator "audio"
    }
}

You can also customize the discriminator column name:

class Content {
    ...
    static mapping = {
        discriminator column: "content_type"
    }
}
class PodCast extends Content {
    ...
    static mapping = {
        discriminator value: "audio"
    }
}

Or you can use a formula:

class Content {
    ...
    static mapping = {
        discriminator value: "1", type: "integer",
            formula: "case when CLASS_TYPE in ('a', 'b', 'c') then 0 else 1 end",
    }
}
class PodCast extends Content {
    ...
    static mapping = {
        discriminator value: "0"
    }
}

dynamicInsert

dynamicInsert

Purpose

Whether to dynamically build INSERT queries

Examples

class Book {

    ...
    static mapping = {
        dynamicInsert true
    }
}

Description

Usage: dynamicInsert(boolean)

By default Hibernate generates all queries at startup and caches them. This helps performance since insert, update, and delete queries don’t have to be dynamically generated at runtime. However, there are certain circumstances where dynamic queries are useful.

For example if you were using custom UserType to hash passwords, every time an UPDATE occurred, the password would get re-hashed. The dynamicInsert method lets you turn off the dynamic creation of queries that uses only the properties that are needed to perform the insert.

dynamicUpdate

dynamicUpdate

Purpose

Whether to dynamically build UPDATE queries

Examples

class Book {

    ...

    static mapping = {
        dynamicUpdate true
    }
}

Description

Usage: dynamicUpdate(boolean)

By default Hibernate generates all queries at startup and caches them. This helps performance since insert, update, and delete queries don’t have to be dynamically generated at runtime. However, there are certain circumstances where dynamic queries are useful.

For example if you were using custom UserType to hash passwords, every time an UPDATE occurred, the password would get re-hashed. The dynamicUpdate method lets you turn off the dynamic creation of queries that uses only the properties that are needed to perform the update.

fetch

fetch

Purpose

Configures the fetching behavior of an association.

Examples

class Author {

    static hasMany = [books: Book]

    static mapping = {
        books fetch: 'join'
    }
}

Description

Usage: association_name(fetch:string)

Arguments:

  • fetchStrategy - The fetching strategy to use. Either join or select.

By default GORM assumes fetching of associations is done using a SELECT when the association is accessed. If you prefer that the association be fetched eagerly at the same time then you can override the behavior:

class Author {

    static hasMany = [books: Book]

    static mapping = {
        books fetch: 'join'
    }
}

Here the books association will be fetched using a join at the same time the author is retrieved, for example:

def author = Author.get(1)
// the books collection is pre-initialized - no risk of lazy loading exceptions

Note that excessive use of joins can be a performance bottleneck. See the section on Eager vs Lazing Fetching in the user guide.

id

id

Purpose

Customizes the way the identifier for a domain class is generated

Examples

class Book {
    static mapping = {
        id generator: 'hilo',
           params: [table: 'hi_value', column: 'next_value', max_lo: 100]
    }
}

Description

Usage: id(map)

Arguments:

  • generator (optional) - The name of the generator to use. Can be increment, identity, sequence, hilo, seqhilo, uuid, guid, native, assigned, select, foreign or sequence-identity. See Hibernate reference documentation for more information.

  • composite (optional) - Takes a list of property names to use that form the composite identifier

  • name (optional) - The property name to use as the identifier

  • params (optional) - Any parameters to pass to the defined identity generator

  • column (optional) - The column name to map the identifier to. The remaining column definition properties are also available.

By default GORM uses the native strategy to generate a database identifier for each entity (typically an auto-incrementing column or a sequence). You can alter this with the id methods generator argument:

static mapping = {
    id generator: 'hilo',
       params: [table: 'hi_value', column: 'next_value', max_lo: 100]
}

You can also use the method to define a composite identifier:

static mapping = {
    id composite: ['title', 'author']
}

or change the name of the property that defines the identifier:

static mapping = {
    id name: 'title'
}

You can also alter the column definition:

static mapping = {
    id column: 'book_id', type: 'integer'
}

See the section on Custom Database Identity in the user guide for more information.

ignoreNotFound

ignoreNotFound

Purpose

Specifies how foreign keys that reference missing rows are handled in many-to-one relationships.

Examples

class LegacyCdDomain {

    String title
    Thumbnail thumbnail

    static mapping = {
        thumbnail ignoreNotFound: true
    }
}
class Thumbnail {
    byte[] data
}

Description

Usage: association_name(ignoreNotFound: boolean)

When the data in the database is corrupt and a foreign key references a non existent record, Hibernate will complain with a "No row with the given identifier exists" message. For example, a LegacyCdDomain record may have a reference to a Thumbnail record with an ID of 1234, but the database may no longer contain a Thumbnail with that ID.

One possible way to load such corrupt data is to use the ignoreNotFound mapping option. If you set it to true, Hibernate will treat a missing row as a null association. So in the above example, our LegacyCdDomain instance would load but its thumbnail property would be null. Specifying a value of false for ignoreNotFound will result in Hibernate throwing an org.hibernate.ObjectNotFoundException.

A dataset loaded with ignoreNotFound: true may throw an exception during save() because of the missing reference!

The default value for this setting is false. It maps to Hibernate’s not-found property.

This settings can be useful if you have a legacy database with unusual behaviour when it comes to referential integrity.

indexColumn

indexColumn

Purpose

Customizes the index column definition of an indexed collection such as a List or Map

Examples

class Neo {

    static hasMany = [matrix: Integer]

    static mapping = {
        matrix indexColumn: [name: "the_matrix", type: Integer]
    }
}
def neo = new Neo()
neo.matrix = [(1): 30, (2): 42, (3): 23]
neo.save(flush: true)

Description

Usage: association_name(indexColumn:map)

Arguments:

  • name - The name of the column as a String

  • type (optional) - The Hibernate type.

  • sqlType (optional) - The underlying SQL type

  • enumType (optional) - The enum type in for type-safe Enum properties. Either ordinal or string.

  • index (optional) - The index name

  • unique (optional) - Whether it is unique

  • length (optional) - The length of the column

  • precision (optional) - The precision of the column

  • scale (optional) - The scale of the column

By default when mapping an indexed collection such as a Map or List the index is stored in a column called association_name_idx which is an integer type in the case of lists and a String in the case of maps. You can alter how the index column is mapped using the indexColumn argument:

static mapping = {
    matrix indexColumn: [name: "the_matrix", type: Integer]
}

insertable

insertable

Purpose

Determines whether a property’s database column is set when a new instance is persisted.

Examples

class Book {

    String title

    static belongsTo = [author: Author]

    static mapping = {
        author insertable: false
        author updateable: false
    }
}

Description

Usage: association_name(insertable: boolean)

Useful in general where you don’t want to set an initial value (or include the column in the generated SQL) during an initial save().

In particular this is useful for one-to-many relationships. For example when you store the foreign key in the child table, it’s often efficient to save the child using only the foreign key of the parent. You do this by setting the parent object (and the parent foreign key) in the child entity. Setting the attributes insertable:false and updateable:false for the belongsTo parent object lets you insert and update using only the foreign key.

static mapping = {
    author insertable: false
}

joinTable

joinTable

Purpose

Customizes the join table used for undirectional one-to-many, many-to-many and primitive collection types.

Examples

Basic collection type:

class Book {

    static hasMany = [chapterPageCounts: Integer]

    static mapping = {
        chapterPageCounts indexColumn: [name: "chapter_number", type: Integer],
                          joinTable: [column: "page_count"]

}

Enum collection types:

enum VehicleStatus { OFF, IDLING, ACCELERATING, DECELERATING }
class Truck {

    static hasMany = [states: VehicleStatus]

    static mapping = {
        states joinTable: [name: 'VEHICLE_STATUS_LOG',
                           key: 'TRUCK_ID', column: 'STATUS']
    }
}

Many-to-many:

class Book {

    String title

    static belongsTo = Author

    static hasMany = [authors: Author]

    static mapping = {
        authors joinTable: [name: "mm_author_books", key: 'mm_book_id' ]
    }
}
class Author {

    String name

    static hasMany = [books: Book]

    static mapping = {
        books joinTable: [name: "mm_author_books", key: 'mm_author_id']
    }
}

Unidirectional One-to-many:

class Employee {

    static hasMany = [projects: Project]

    static mapping = {
        projects joinTable: [name: 'EMP_PROJ',
                             column: 'PROJECT_ID',
                             key: 'EMPLOYEE_ID']
    }
}
class Project {  }

Description

Usage: association_name(joinTable:map)

Arguments:

  • name - The table name

  • key (optional) - The foreign key

  • column (optional) - The inverse column

GORM has various strategies for mapping association types. Some of them, such as basic collection types and many-to-many associations, use a join table. You can customize how this join table is created using the joinTable argument.

lazy

lazy

Purpose

Configures whether to use proxies and lazy loading for one-to-one and many-to-one associations.

Examples

class Book {

    static belongsTo = [author: Author]

    static mapping = {
        author lazy: false
    }
}

Description

Usage: association_name(lazy: boolean)

By default GORM single-ended associations are lazy in that when you load a domain instance, an associated domain is not loaded until accessed. Hibernate creates a dynamic proxy by subclassing the domain class and proxying all methods and property access.

This can have some strange side effects (see this page on proxies at the Hibernate site) particularly in relation to inheritance. You can tell Hibernate not use proxies for single-ended associations by using the lazy argument:

static mapping = {
    author lazy: false
}

See the section on Eager vs Lazing Fetching in the user guide.

order

order

Purpose

Customizes the default sort order of query results.

Examples

class Book {
    ...
    static mapping = {
        order "desc"
    }
}

Description

Usage: order(string)

Arguments:

  • direction - Either "desc" or "asc" for descending and ascending respectively.

By defaults results are sorted in ascending order. With the order method you can alter results to be sorted in descending order. See also the sort method.

sort

sort

Purpose

Customizes the default property to sort by for query results.

Examples

class Book {
    ...
    static mapping = {
        sort "releaseDate"
    }
}

Description

Usage: sort(string/map)

By default results are sorted by creation date, and you can specify the column to order by in a query:

def results = Book.list(sort:"title")

However, you can also configure the default sort property:

static mapping = {
    sort "title"
}

in which case the sort argument is no longer needed. You can also control the sort order:

static mapping = {
    sort title: "desc" // or "asc"
}

table

table映射

目的

自定义的domain类关联的数据库表的名称

示例

class Book {
    static mapping = {
        table "book_catalog"
    }
}

描述

Usage: table(string/map)

Arguments:

  • name - 表的名称

  • schema (可选) - 表的schema

  • catalog (可选) - 表的catalog

默认情况下,domain类的表的映射名字是基于类的名字。GORM将类名的java风格驼峰格式映射为表名时,使用下划线隔离。例如` productreview 成为 product_review `。你可以用`table`方法重写表名:

static mapping = {
    table "book_catalog"
}

也可以指定 schema 和 catalog名称:

static mapping = {
    table name: "book_catalog", schema: "dbo", catalog: "CRM"
}

type

type

Purpose

Configures the Hibernate type for a particular property.

Examples

Changing to a text type (CLOB or TEXT depending on database dialect):

class Book {

    String title

    static mapping = {
        title type: "text"
    }
}

User types with multiple columns:

class Book {
    ...
    MonetaryAmount amount

    static mapping = {
        amount type: MonetaryUserType, {
            column name: "value"
            column name: "currency", sqlType: "char", length: 3
        }
    }
}

Description

Usage: association_name(type:string/class)

Hibernate will attempt to automatically select the appropriate database type from the field typed based on configuration in the Dialect class that is being used. But you can override the defaults if necessary. For example String values are mapped by default to varchar(255) columns. To store larger String values you can use a text type instead:

static mapping = {
    title type: "text"
}

Hibernate also has the concept of custom UserType implementations. In this case you specify the UserType class. If the UserType maps to multiple columns you may need to specify a mapping for each column:

static mapping = {
    amount type: MonetaryUserType, {
        column name: "value"
        column name: "currency", sqlType: "char", length: 3
    }
}

updateable

updateable映射

Purpose

Determines whether a property’s database column is updated when persistent instances are updated.

Examples

class Book {

    String title

    static belongsTo = [author: Author]

    static mapping = {
        author insertable: false
        author updateable: false
    }
}

Description

Usage: association_name(updateable: boolean)

Useful in general where you don’t want to update a value (or include the column in the generated SQL) during a save().

In particular this is useful for one-to-many relationships. For example when you store the foreign key in the child table, it’s often efficient to save the child using only the foreign key of the parent. You do this by setting the parent object (and the parent foreign key) in the child entity. Setting the attributes insertable:false and updateable:false for the belongsTo parent object lets you insert and update using only the foreign key.

static mapping = {
    author updateable: false
}

version

version映射

目的

用于禁用乐观锁定或更改保持版本的列.

示例

class Book {
    ...
    static mapping = {
        version false
    }
}

描述

Usage: version(string/boolean)

默认情况下,GORM配置 optimistic locking 启用. 可以通过设置 version 方法的 `false`参数来禁用:

static mapping = {
    version false
}

可以将名称传递到 `version`方法以更改数据库列的名称:

static mapping = {
    version 'revision_number'
}