SlideShare una empresa de Scribd logo
1 de 108
By: Saurabh Dixit
 Automatically maps domain objects to
database
 Provides query and update facility
1. Finding objects in persistence store(find
by methods)
2. Persistence life cycle methods
3. Criteria and HQL query facilities
 Grails injects GORM functionality into objects
in run time
 Declare properties for the domain class
1.The id and version properties are injected
automatically.
2. All properties are not null/required by
default.
 Associations
 One‐to‐one, one‐to‐many, many‐to‐many
 Uni‐directional and bi‐directional
 Owners defined by using belongsTo
property
 Many-to-one relationship:
 A Many-to-one relationship is the
simplest kind, and is defined with a
property of the type of another domain
class. Consider this example:
 A unidirectional many-to-one
relationship from Face to Nose:
 class Face {
Nose nose
}
class Nose {
}
 To make this relationship bidirectional define
the other side as follows:
class Face {
Nose nose
}
class Nose {
static belongsTo = [face:Face]
}
 The result of this is that we can create a Face,
attach a Nose instance to it and when we
save or delete the Face instance, GORM will
save or delete the Nose. In other words, saves
and deletes will cascade from
Face to the associated Nose:
Face f = new Face()
f.nose = new Nose()
f.save()
 one-to-one Relationship:
 use the hasOne property on the owning
side, e.g. Face:
classAuthor {
static hasOne = [book:Book]
}
class Book {
Author author
}
 Note that using this property puts the
foreign key on the inverse table to the
previous example, so in this case the
foreign key column is stored in the nose
table inside a column called face_id.
 hasOne only works with bidirectional
relationships.
 it's a good idea to add a unique constraint on
one side of the one-to-one relationship:
classAuthor {
static hasOne = [book:Book]
static constraints = {
book unique: true
}
}
class Book {
Author author
}
 One-to-many Relationship:
classAuthor {
static hasMany = [books: Book]
String name
}
class Book {
String title
}
 In this case we have a unidirectional one-to-
many. Grails will, by default, map this kind of
relationship with a join table.
 Grails will automatically inject a property of
type java.util.Set into the domain class based
on the hasMany setting.This can be used to
iterate over the collection:
def a = Author.get(1)
for (book in a.books) {
println book.title
}
 The default fetch strategy used by Grails is
"lazy", which means that the collection will be
lazily initialized on first access.
 The default cascading behaviour is to cascade
saves and updates, but not deletes unless a
belongsTo is also specified:
classAuthor {
static hasMany = [books: Book]
String name
}
class Book {
static belongsTo = [author: Author]
String title
}
 If you have two properties of the same type
on the many side of a one-to-many you have
to use mappedBy to specify which the
collection is mapped:
classAirport {
static hasMany = [flights: Flight]
static mappedBy = [flights: "departureAirport"]
}
class Flight {
Airport departureAirport
Airport destinationAirport
}
 Many-to-many Relationship:
 Grails supports many-to-many relationships by
defining a hasMany on both sides of the relationship
and having a belongsTo on the owned side of the
relationship:
class Book {
static belongsTo = Author
static hasMany = [authors:Author]
String title
}
classAuthor {
static hasMany = [books:Book]
String name
}
 Grails maps a many-to-many using a join
table at the database level.The owning side
of the relationship, in this case Author, takes
responsibility for persisting the relationship
and is the only side that can cascade saves
across.
 Relationship with the basic collection type:
 As well as associations between different
domain classes, GORM also supports
mapping of basic collection types.
 For example, the following class creates a
nicknames association that is a Set of String
instances:
class Person {
static hasMany = [nicknames: String]
}
 GORM will map an association like the above
using a join table.
 You can alter various aspects of how the join
table is mapped using the joinTable
argument:
class Person {
static hasMany = [nicknames: String]
static mapping = {
hasMany joinTable: [name: 'bunch_o_nicknames',
key: 'person_id',
column: 'nickname',
type: "text"]
}
}
 As well as association, Grails supports the notion
of composition.
 In this case instead of mapping classes onto
separate tables a class can be "embedded" within
the current table.
 For example:
class Person {
Address homeAddress
Address workAddress
static embedded = ['homeAddress', 'workAddress']
}
classAddress {
String number
String code
}
 The resulting mapping would looking like
this:
If you define the Address class in a separate
Groovy file in the grails-app/domain
directory you will also get an address table.
 Custom mappings are defined using a static
mapping block defined within your domain
class:
class Person {
…
static mapping = {
version false
autoTimestamp false
}
}
 You can also configure global mappings in
Config.groovy (or an external config file)
using this setting:
grails.gorm.default.mapping = {
version false
autoTimestamp false
}
class Person {
String firstName
Sting address
static mapping = {
version false
autoTimestamp false
table 'people' //Table name
firstName column: 'First_Name' // column name
address type:'text'
}
}
 for the type in mapping you can create user
defined types using hibernate
org.hibernate.usertype Interface UserType.
 GORM supports inheritance both from
abstract base classes and concrete persistent
GORM entities.
 Inheritance hierarchies
 Table‐per‐hierarchy:All classes map to a
single table
 Table‐per‐subclass: Each class maps to its
own table and JOINs are used
 For example:
classContent {
String author
}
class BlogEntry extends Content {
URL url
}
class Book extends Content {
String ISBN
}
class PodCast extends Content {
byte[] audioStream
}
 In the above example we have a parent
Content class and then various child classes
with more specific behavior.
 At the database levelGrails by default uses
table-per-hierarchy mapping with a
discriminator column called class so the
parent class (Content) and its subclasses
(BlogEntry, Book etc.), share the same table.
 By default same table, forTable-per-
hierarchy.
 Table-per-hierarchy mapping has a down side
in that you cannot have non-nullable
properties with inheritance mapping.
 To have two different tables for them: use
table-per-hierarchy=false
 To use table per subclass:
▪ tablePerHierarchy false
 Retrieving Objects:
 get(), getAll(), read()
 Listing objects:
 list(), listOrderBy*() methods
 order, sort, offset, and max named
arguments
 Sets:
 Sets of Objects
 By default when you define a relationship
withGORM it is a java.util.Set which is an
unordered collection that cannot contain
duplicates. In other words when you have:
classAuthor {
static hasMany = [books: Book]
}
 The books property that GORM injects is a
java.util.Set. Sets guarantee uniquenes but
not order, which may not be what you want.
To have custom ordering you configure the
Set as a SortedSet:
class Author {
SortedSet books
static hasMany = [books: Book]
}
 In the above case a java.util.SortedSet
implementation is used which means you
must implement java.lang.Comparable in
your Book class:
class Book implements Comparable {
String title
Date releaseDate = new Date()
int compareTo(obj) {
releaseDate.compareTo(obj.releaseDate)
}
}
 Lists of Objects:
 To keep objects in the order which they were
added and to be able to reference them by index
like an array you can define your collection type
as a List:
classAuthor {
List books
static hasMany = [books: Book]
}
 In this case when you add new elements to the
books collection the order is retained in a
sequential list indexed from 0 so you can do:
author.books[0] // get the first book
 Bags of Objects:
 If ordering and uniqueness aren't a concern
(or if you manage these explicitly) then you
can use the Hibernate Bag type to represent
mapped collections.
 The only change required for this is to define
the collection type as a Collection:
classAuthor {
Collection books
static hasMany = [books: Book]
}
 Since uniqueness and order aren't managed
by Hibernate, adding to or removing from
collections mapped as a Bag don't trigger a
load of all existing instances from the
database, so this approach will perform
better and require less memory than using a
Set or a List.
 Maps of Objects:
 If you want a simple map of string/value pairs
GORM can map this with the following:
classAuthor {
Map books // map of ISBN:book names
}
def a = newAuthor()
a.books = ["1590597583":"Grails Book"]
a.save()
 In this case the key and value of the map
MUST be strings.
 If you want a Map of objects then you can do
this:
class Book {
Map authors
static hasMany = [authors: Author]
}
def a = new Author(name:"Stephen King")
def book = new Book()
book.authors = [stephen:a]
book.save()
 CollectionTypes and Performance:
 The Java Set type doesn't allow duplicates.To
ensure uniqueness when adding an entry to a
Set association Hibernate has to load the
entire associations from the database.
 If you have a large numbers of entries in the
association this can be costly in terms of
performance.
 The same behavior is required for List types,
since Hibernate needs to load the entire
association to maintain order.Therefore it is
recommended that if you anticipate a large
numbers of records in the association that
you make the association bidirectional so
that the link can be created on the inverse
side.
 For example consider the following code:
def book = new Book(title:"New Grails Book")
def author =Author.get(1)
book.author = author
book.save()
 In this example the association link is being
created by the child (Book) and hence it is not
necessary to manipulate the collectiodirectly
resulting in fewer queries and more efficient
code.
 Given an Author with a large number of
associated Book instances if you were to
write code like the following you would see
an impact on performance:
def book = new Book(title:"New Grails Book")
def author =Author.get(1)
author.addToBooks(book)
author.save()
 You could also model the collection as a
Hibernate Bag as described above.
 By default Lazy fetching, object will be loaded
only when it will be accessed.
 Lazy can be set to false to enable eager fetching:
classAirport {
String name
static hasMany = [flights: Flight]
static mapping = {
flights lazy: false
}
}
 In this case the flights association will be
loaded at the same time as its Airport
instance
 Although eager fetching is appropriate for
some cases, it is not always desirable.
 If you made everything eager you could quite
possibly load your entire database into
memory resulting in performance and
memory problems.
 An alternative to eager fetching is to use
batch fetching.You can configure Hibernate
to lazily fetch results in "batches".
 For example:
classAirport {
String name
static hasMany = [flights: Flight]
static mapping = {
flights batchSize: 10
}
}
 In this case, due to the batchSize argument,
when you iterate over the flights association,
Hibernate will fetch results in batches of 10.
 For example:
 If you had an Airport that had 30 flights,
 if you didn't configure batch fetching you
would get 1 query to fetch the Airport and
then 30
 queries to fetch each flight:
 With batch fetching you get 1 query to fetch
the Airport and 3 queries to fetch each
Flight in batches of 10.
 In other words:
batch fetching is an optimization of the
lazyfetching strategy.
 Batch fetching can also be configured at the
class level as follows:
class Flight {
…
static mapping = {
batchSize 10
}
}
 Optimistic Locking:
 By default GORM classes are configured for
optimistic locking.
 Optimistic locking is a feature of Hibernate
which involves storing a version value in a
special version column in the database that is
incremented after each update.
 The version column gets read into a version
property that contains the current versioned
state of persistent instance which you can
access:
def airport = Airport.get(10)
println airport.version
 When you perform updates Hibernate will
automatically check the version property against
the version column in the database and if they
differ will throw a StaleObjectException.This will
rollback the transaction if one is active.
 The version will only be updated after
flushing the session.
 Dealing with the locking through exception
handling:
def airport = Airport.get(10)
try { airport.name = "Heathrow"
airport.save(flush: true)
}
catch (org.springframework.dao.OptimisticLockingFailureException e) {
// deal with exception
}
 The way you deal with the exception depends
on the application.You could attempt a
programmatic merge of the data or go back
to the user and ask them to resolve the
conflict.
 Pessimistic Locking:
 Pessimistic locking is equivalent to doing a
SQL "SELECT * FOR UPDATE" statement
and locking a row in the database.
 This has the implication that other read
operations will be blocking until the lock is
released.
 In Grails pessimistic locking is performed on an
existing instance with the lock method:
def airport = Airport.get(10)
airport.lock() // lock for update
airport.name = "Heathrow"
airport.save()
 Grails will automatically deal with releasing the
lock for you once the transaction has been
committed.
 In the above case what we are doing is
"upgrading" from a regular SELECT to a
SELECT..FOR UPDATE and another thread could
still have updated the record in between the call to
get() and the call to lock().
 To get around this problem you can use the
static lock method that takes an id just like
get:
def airport = Airport.lock(10) // lock for update
airport.name = "Heathrow"
airport.save()
 Using pessimistinc locking in dynamic finders
and criteria:
 As well as the lock method you can also obtain a
pessimistic locking using queries.
 For example using a dynamic finder:
def airport = Airport.findByName("Heathrow", [lock: true])
 Or using criteria:
def airport = Airport.createCriteria().get {
eq('name', 'Heathrow')
lock true
}
 You can use the isDirty method to check if
any field has been modified:
def airport = Airport.get(10)
assert !airport.isDirty()
airport.properties = params
if (airport.isDirty()) {
// do something based on changed state
}
 isDirty() does not currently check collection
associations, but it does check all other
persistent properties and associations.
 You can also check if individual fields have
been modified:
def airport = Airport.get(10)
assert !airport.isDirty()
airport.properties = params
if (airport.isDirty('name')) {
// do something based on changed name
}
 getDirtyPropertyNames:
 You can use the getDirtyPropertyNames
method to retrieve the names of modified
fields; this may be empty but will not be
null:
def airport = Airport.get(10)
assert !airport.isDirty()
airport.properties = params
def modifiedFieldNames = airport.getDirtyPropertyNames()
for (fieldName in modifiedFieldNames) {
// do something based on changed value
}
 getPersistentValue:
 You can use the getPersistentValue method
to retrieve the value of a modified field:
def airport = Airport.get(10)
assert !airport.isDirty()
airport.properties = params
def modifiedFieldNames = airport.getDirtyPropertyNames()
for (fieldName in modifiedFieldNames) {
def currentValue = airport."$fieldName"
def originalValue = airport.getPersistentValue(fieldName)
if (currentValue != originalValue) {
// do something based on changed value
}
}
 Use property names of the class
 Support for many expressions in finder
method
def book = Book.findByTitle("The Stand")
book = Book.findByTitleLike("Harry Pot%")
 Like is comparator, due to the Like
comparator, above finder is equivalent to a
SQL like expression.
 The possible comparators include:
InList In the list of given values
LessThan less than a given value
LessThanEquals less than or equal a give value
GreaterThan greater than a given value
GreaterThanEquals greater than or equal a given value
Like Equivalent to a SQL like expression
Ilike Similar to a Like, except case insensitive
NotEqual Negates equality
Between Between two values (requires two
arguments)
IsNotNull Not a null value (doesn't take an argument)
IsNull Is a null value (doesn't take an argument)
 Between, IsNotNull and IsNull require
different numbers of method arguments
compared to the rest, as demonstrated in the
following example:
def now = new Date()
def lastWeek = now - 7
def book = Book.findByReleaseDateBetween(lastWeek, now)
books = Book.findAllByReleaseDateIsNull()
books = Book.findAllByReleaseDateIsNotNull()
 Boolean logic (AND/OR):
 Method expressions can also use a boolean
operator to combine two or more criteria:
def books = Book.findAllByTitleLikeAndReleaseDateGreaterThan(
"%Java%", new Date() - 30)
 In this case we're using And in the middle of
the query to make sure both conditions are
satisfied, but you could equally use Or:
def books = Book.findAllByTitleLikeOrReleaseDateGreaterThan(
"%Java%", new Date() - 30)
 Built on Hibernate’s CriteriaAPI
 Groovy builder is used to build up the criteria
▪ Hierarchy of method calls and closures for
building tree‐like structures
 Each domain class has a createCriteria()
method
▪ Call get, list, scroll, or count on criteria
▪ The criteria builder is used to restrict the
query
 Supports associations and projections
 Some Criteria queries:
def c = Account.createCriteria()
def results = c.list {
like("holderFirstName", "Fred%")
and {
between("balance", 500, 1000)
eq("branch", "London")
}
maxResults(10)
order("holderLastName", "desc")
}
 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
(caseinsensitive)
A version of eq that supports an
optional 3rd Map parameter to
specify that the query be
caseinsensitive.
eq("branch", "london",
[ignoreCase: true])
eqProperty Where one property must equal
another
eqProperty("lastTx", "firstTx")
Node Description Example
gt Where a property is greater than a particular
value
gt("balance",1000)
gtProperty Where a 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 a 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 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")
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 a 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 a 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()
 Criteria can be written as:
def query = {
and {
eq('survey', survey)
eq('user',user)
}
}
FormSubmission.createCriteria().list(query)
or
FormSubmission.createCriteria().list{
and {
eq('survey', survey)
eq('user',user)
}
}
 Adding SQLRestrictions in a criteria:
 Find all the users with first name, lastname
dob, but their status should not be null or
test_user, and their role should be
ROLE_USER in userrole table.
 User UserRole classes are created by
springSecurityPlugin:
Role userRole =
Role.findByAuthority('ROLE_USER');
UserList = User.createCriteria().list{
and{
if(params.firstName){
ilike('firstName',params.firstName+'%')
}
if(params.lastName){
ilike('lastName', params.lastName+'%')
}
if(birthDate){
eq('birth', birthDate)
}
sqlRestriction("({alias}.status IS NULLOR
CAST({alias}.statusAS nvarchar) !=
'test_user')AND ${userRole.id} in (Select
ur.role_id from user_role ur where
ur.user_id={alias}.id)")
}
if (!params.offset) {
params.offset = 0
}
if (!params.max) {
params.max = 10
}
maxResults(params.max.toInteger())
firstResult(params.offset.toInteger())
}
 Support for HibernateQuery Language:
 find(hql), findAll(hql), and executeQuery(hql) for
queries
 executeUpdate(hql) for DML‐style opera3ons
(sets of updates or deletes)
 Support for positional and named parameters
EAVEntity.executeQuery("SELECT e.id FROM EAVEntity eWHERE
e.initialEntryBy=:entryFor AND e.attribute=:attrId",
[entryFor:''+entryFor+'', attrId: this.parentAttribute])
 // 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 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'])
 // 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])
 The executeQuery method allows the
execution of arbitrary HQL queries.
 HQL queries can return domain class
instances, or Arrays 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)
 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
 Support forWriting native queries:
 Defining new SQL instance: creating a new sql
instance, basically it will create a new instance of
the connection:
Sql sql = Sql.newInstance(dataSource)
 Then we can execute the methods on the sql.
sql.rows("SELECT id FROM eavchoice_entity_valueWHERE
entity_id=:id",[id:newEntityId]);
String entityInsertQuery = "insert into eaventity (version, attribute_id,
initial_entry_by)VALUES (0, $attributeId, '$entryFor')";
def newEntity = sql.executeInsert(entityInsertQuery);
sql.close()
 Using ExplicitTransaction with Native sql
queries:
▪ // Creating sql instance
Sql sql = Sql.newInstance(dataSource)
▪ // Instantiating transaction manager
DataSourceTransactionManager txm = new
DataSourceTransactionManager(dataSource)
 // instantiating transaction through
transaction manager
def status = txm.getTransaction( new DefaultTransactionDefinition() )
try{
/*
Write sql queries
*/
sql.close()
txm.commit(status)
}catch(Exception e){
log.error("Exception in saving data", e)
//Transaction roll back
txm.rollback(status)
}finally(){
sql.close()
//Cleanup resources after transaction completion.
txm.cleanupAfterCompletion( status )
}
 Where Queries:
 The where method, introduced in Grails 2.0,
builds on the support for Detached Criteria by
providing an enhanced, compile-time checked
query DSL for common queries.
 The where method is more flexible than dynamic
finders, less verbose than criteria and provides a
powerful mechanism to compose queries.
 Basic Querying:
 The where method accepts a closure that looks
very similar to Groovy's regular collection
methods.
 The closure should define the logical criteria in
regular Groovy syntax, for example:
def query = Person.where {
firstName == "Bart"
}
Person bart = query.find()
 The returned object is a DetachedCriteria
instance, which means it is not associated with
any particular database connection or session.
 This means you can use the where method to
define common queries at the class level:
class Person {
static simpsons = where {
lastName == "Simpson"
}
…
}
 Query execution is lazy and only happens upon
usage of the DetachedCriteria instance.
 If you want to execute a where-style query
immediately there are variations of the findAll
and find methods to accomplish this:
def results = Person.findAll {
lastName == "Simpson"
}
def results = Person.findAll(sort:"firstName") {
lastName == "Simpson"
}
Person p = Person.find { firstName == "Bart" }
 Each Groovy operator maps onto a regular criteria method.
 The following table provides a map of Groovy operators to
methods:
Operator Criteria Method Description
== eq Equal to
!= ne Not Equal to
> gt Greater than
< lt Less than
>= ge Greater than or equal to
<= le Less than or equal to
in inList Contained within the given list
==~ like Like a given string
=~ ilike Case insensitive like
 It is possible use regular Groovy comparison
operators and logic to formulate complex queries:
def query = Person.where {
(lastName != "Simpson" && firstName != "Fred") || (firstName == "Bart" &&
age > 9)
}
def results = query.list(sort:"firstName")
 The Groovy regex matching operators map onto like
and ilike queries unless the expression on the right hand
side is a Pattern object, in which case they map onto an
rlike query:
def query = Person.where {
firstName ==~ ~/B.+/
}
 ** Note that rlike queries are only supported if the underlying database supports regular
expressions
 A between criteria query can be done by combining
the in keyword with a range:
def query = Person.where {
age in 18..65
}
 Finally, you can do isNull and isNotNull style queries
by using null with regular comparison operators:
def query = Person.where {
middleName == null
}
 Query Composition:
 Since the return value of the where method is a
DetachedCriteria instance you can compose new
queries from the original query:
def query = Person.where {
lastName == "Simpson"
}
def bartQuery = query.where {
firstName == "Bart"
}
Person p = bartQuery.find()
 Note that you cannot pass a closure defined as a
variable into the where method unless it has been
explicitly cast to a DetachedCriteria instance.
 In other words the following will produce an error:
def callable = {
lastName == "Simpson"
}
def query = Person.where(callable)
 The above must be written as follows:
import grails.gorm.DetachedCriteria
def callable = {
lastName == "Simpson"
} as DetachedCriteria<Person>
def query = Person.where(callable)
 As you can see the closure definition is cast (using
the Groovy as keyword) to a DetachedCriteria
instance targeted at the Person class.
 Conjunction, Disjunction and Negation:
 As mentioned previously you can combine regular
Groovy logical operators (|| and &&) to form
conjunctions and disjunctions:
def query = Person.where {
(lastName != "Simpson" && firstName != "Fred") || (firstName == "Bart" &&
age > 9)
}
 You can also negate a logical comparison using !:
def query= Person.where {
firstName == "Fred" && !(lastName == 'Simpson')
}
 Property Comparison Queries:
 If you use a property name on both the left hand
and right side of a comparison expression then
the appropriate property comparison criteria is
automatically used:
def query = Person.where {
firstName == lastName
}
 The following table described how each comparison
operator maps onto each criteria property
comparison method:
Operator Criteria Method Description
== eqProperty Equal to
!= neProperty Not equal to
> gtProperty Greater than
< ltProperty Less than
>= geProperty Greater than or equal
to
<= leProperty Less than or equal to
 Querying Associations:
 Associations can be queried by using the dot
operator to specify the property name of the
association to be queried:
def query = Pet.where {
owner.firstName == "Joe" || owner.firstName == "Fred"
}
 You can group multiple criterion inside a closure
method call where the name of the method
matches the association name:
def query = Person.where {
pets { name == "Jack" || name == "Joe" }
}
 This technique can be combined with other top-
level criteria:
def query = Person.where {
pets { name == "Jack" } || firstName == "Ed"
}
 For collection associations it is possible to
apply queries to the size of the collection:
def query = Person.where {
pets.size() == 2
}
 Subqueries:
 It is possible to execute subqueries within where
queries. For example to find all the people older
than the average age the following query can be
used:
final query = Person.where {
age > avg(age)
}
 The following table lists the possible
subqueries:
Method Description
avg The average of all values
sum The sum of all values
max The maximum value
min The minimum value
count The count of all values
property Retrieves a property of the resulting
entities
 You can apply additional criteria to any subquery by
using the of method and passing in a closure containing
the criteria:
def query = Person.where {
age > avg(age).of { lastName == "Simpson" } && firstName == "Homer"
}
 Since the property subquery returns multiple results,
the criterion used compares all results.
 For example the following query will find all people
younger than people with the surname "Simpson":
Person.where {
age < property(age).of { lastName == "Simpson" }
}
 There are several functions available to you within the
context of a query.These are summarized in the table below:
Method Description
second The second of a date property
minute The minute of a date property
hour The hour of a date property
day The day of the month of a date property
month The month of a date property
year The year of a date property
upper Converts a string property to upper case
lower Converts a string property to lower case
length The length of a string property
trim Trims a string property
 **Currently functions can only be applied to properties
or associations of domain classes.You cannot, for
example, use a function on a result of a subquery.
 For example the following query can be used to find
all pet's born in 2011:
def query = Pet.where {
year(birthDate) == 2011
}
 You can also apply functions to associations:
def query = Person.where {
year(pets.birthDate) == 2009
}
 Batch Updates and Deletes:
▪ Since each where method call returns a
DetachedCriteria instance, you can use where queries to
execute batch operations such as batch updates and
deletes.
▪ For example, the following query will update all people
with the surname "Simpson" to have the surname
"Bloggs":
def query = Person.where {
lastName == 'Simpson'
}
int total = query.updateAll(lastName:"Bloggs")
 **Note that one limitation with regards to batch
operations is that join queries (queries that query
associations) are not allowed.
 To batch delete records you can use the deleteAll
method:
def query = Person.where {
lastName == 'Simpson'
}
int total = query.deleteAll()
Grails object relational mapping: GORM
Grails object relational mapping: GORM

Más contenido relacionado

La actualidad más candente

REST APIs with Spring
REST APIs with SpringREST APIs with Spring
REST APIs with SpringJoshua Long
 
Nitro for your Grails App: how to improve performance. Greach '18
Nitro for your Grails App: how to improve performance. Greach '18Nitro for your Grails App: how to improve performance. Greach '18
Nitro for your Grails App: how to improve performance. Greach '18Alberto De Ávila Hernández
 
JavaScript Event Loop
JavaScript Event LoopJavaScript Event Loop
JavaScript Event LoopDesignveloper
 
Node.js File system & Streams
Node.js File system & StreamsNode.js File system & Streams
Node.js File system & StreamsEyal Vardi
 
MongoDB Aggregation Framework
MongoDB Aggregation FrameworkMongoDB Aggregation Framework
MongoDB Aggregation FrameworkCaserta
 
Javascript - Array - Creating Array
Javascript - Array - Creating ArrayJavascript - Array - Creating Array
Javascript - Array - Creating ArraySamuel Santos
 
Java Spring framework, Dependency Injection, DI, IoC, Inversion of Control
Java Spring framework, Dependency Injection, DI, IoC, Inversion of ControlJava Spring framework, Dependency Injection, DI, IoC, Inversion of Control
Java Spring framework, Dependency Injection, DI, IoC, Inversion of ControlArjun Thakur
 
Intro to Asynchronous Javascript
Intro to Asynchronous JavascriptIntro to Asynchronous Javascript
Intro to Asynchronous JavascriptGarrett Welson
 
Building Grails applications with PostgreSQL
Building Grails applications with PostgreSQLBuilding Grails applications with PostgreSQL
Building Grails applications with PostgreSQLCommand Prompt., Inc
 
Dynamically Generate a CRUD Admin Panel with Java Annotations
Dynamically Generate a CRUD Admin Panel with Java AnnotationsDynamically Generate a CRUD Admin Panel with Java Annotations
Dynamically Generate a CRUD Admin Panel with Java AnnotationsBroadleaf Commerce
 
HTML5 Local Storage
HTML5 Local StorageHTML5 Local Storage
HTML5 Local StorageLior Zamir
 
Closures in Javascript
Closures in JavascriptClosures in Javascript
Closures in JavascriptDavid Semeria
 
Spring Framework - AOP
Spring Framework - AOPSpring Framework - AOP
Spring Framework - AOPDzmitry Naskou
 

La actualidad más candente (20)

REST APIs with Spring
REST APIs with SpringREST APIs with Spring
REST APIs with Spring
 
Nitro for your Grails App: how to improve performance. Greach '18
Nitro for your Grails App: how to improve performance. Greach '18Nitro for your Grails App: how to improve performance. Greach '18
Nitro for your Grails App: how to improve performance. Greach '18
 
JavaScript Event Loop
JavaScript Event LoopJavaScript Event Loop
JavaScript Event Loop
 
Node.js File system & Streams
Node.js File system & StreamsNode.js File system & Streams
Node.js File system & Streams
 
MongoDB Aggregation Framework
MongoDB Aggregation FrameworkMongoDB Aggregation Framework
MongoDB Aggregation Framework
 
Angular js
Angular jsAngular js
Angular js
 
Jquery
JqueryJquery
Jquery
 
Javascript - Array - Creating Array
Javascript - Array - Creating ArrayJavascript - Array - Creating Array
Javascript - Array - Creating Array
 
Spring Boot Tutorial
Spring Boot TutorialSpring Boot Tutorial
Spring Boot Tutorial
 
Java Spring framework, Dependency Injection, DI, IoC, Inversion of Control
Java Spring framework, Dependency Injection, DI, IoC, Inversion of ControlJava Spring framework, Dependency Injection, DI, IoC, Inversion of Control
Java Spring framework, Dependency Injection, DI, IoC, Inversion of Control
 
Intro to Asynchronous Javascript
Intro to Asynchronous JavascriptIntro to Asynchronous Javascript
Intro to Asynchronous Javascript
 
Building Grails applications with PostgreSQL
Building Grails applications with PostgreSQLBuilding Grails applications with PostgreSQL
Building Grails applications with PostgreSQL
 
Java script ppt
Java script pptJava script ppt
Java script ppt
 
Dynamically Generate a CRUD Admin Panel with Java Annotations
Dynamically Generate a CRUD Admin Panel with Java AnnotationsDynamically Generate a CRUD Admin Panel with Java Annotations
Dynamically Generate a CRUD Admin Panel with Java Annotations
 
HTML5 Local Storage
HTML5 Local StorageHTML5 Local Storage
HTML5 Local Storage
 
Closures in Javascript
Closures in JavascriptClosures in Javascript
Closures in Javascript
 
Spring Boot
Spring BootSpring Boot
Spring Boot
 
jQuery
jQueryjQuery
jQuery
 
Spring Framework - AOP
Spring Framework - AOPSpring Framework - AOP
Spring Framework - AOP
 
Introduction to Spring Boot
Introduction to Spring BootIntroduction to Spring Boot
Introduction to Spring Boot
 

Similar a Grails object relational mapping: GORM

Similar a Grails object relational mapping: GORM (20)

Programming in Java: Combining Objects
Programming in Java: Combining ObjectsProgramming in Java: Combining Objects
Programming in Java: Combining Objects
 
Gorm
GormGorm
Gorm
 
Advance GORM
Advance GORMAdvance GORM
Advance GORM
 
GORM
GORMGORM
GORM
 
GORM
GORMGORM
GORM
 
Introduction to es6
Introduction to es6Introduction to es6
Introduction to es6
 
Java Collections Tutorials
Java Collections TutorialsJava Collections Tutorials
Java Collections Tutorials
 
Hibernate collections
Hibernate  collectionsHibernate  collections
Hibernate collections
 
Jscript part2
Jscript part2Jscript part2
Jscript part2
 
Java Collection
Java CollectionJava Collection
Java Collection
 
Scala idioms
Scala idiomsScala idioms
Scala idioms
 
A Scala tutorial
A Scala tutorialA Scala tutorial
A Scala tutorial
 
9. Object Relational Databases in DBMS
9. Object Relational Databases in DBMS9. Object Relational Databases in DBMS
9. Object Relational Databases in DBMS
 
Collections
CollectionsCollections
Collections
 
Grails 0.3-SNAPSHOT Presentation WJAX 2006 English
Grails 0.3-SNAPSHOT Presentation WJAX 2006 EnglishGrails 0.3-SNAPSHOT Presentation WJAX 2006 English
Grails 0.3-SNAPSHOT Presentation WJAX 2006 English
 
OO in JavaScript
OO in JavaScriptOO in JavaScript
OO in JavaScript
 
Prototype Utility Methods(1)
Prototype Utility Methods(1)Prototype Utility Methods(1)
Prototype Utility Methods(1)
 
03 Object Relational Mapping
03 Object Relational Mapping03 Object Relational Mapping
03 Object Relational Mapping
 
Dependency Injection in Spring
Dependency Injection in SpringDependency Injection in Spring
Dependency Injection in Spring
 
05-OOP-Abstract Classes____________.pptx
05-OOP-Abstract Classes____________.pptx05-OOP-Abstract Classes____________.pptx
05-OOP-Abstract Classes____________.pptx
 

Último

Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilV3cube
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 

Último (20)

Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 

Grails object relational mapping: GORM

  • 2.  Automatically maps domain objects to database  Provides query and update facility 1. Finding objects in persistence store(find by methods) 2. Persistence life cycle methods 3. Criteria and HQL query facilities
  • 3.  Grails injects GORM functionality into objects in run time  Declare properties for the domain class 1.The id and version properties are injected automatically. 2. All properties are not null/required by default.
  • 4.  Associations  One‐to‐one, one‐to‐many, many‐to‐many  Uni‐directional and bi‐directional  Owners defined by using belongsTo property
  • 5.  Many-to-one relationship:  A Many-to-one relationship is the simplest kind, and is defined with a property of the type of another domain class. Consider this example:  A unidirectional many-to-one relationship from Face to Nose:  class Face { Nose nose } class Nose { }
  • 6.  To make this relationship bidirectional define the other side as follows: class Face { Nose nose } class Nose { static belongsTo = [face:Face] }
  • 7.  The result of this is that we can create a Face, attach a Nose instance to it and when we save or delete the Face instance, GORM will save or delete the Nose. In other words, saves and deletes will cascade from Face to the associated Nose: Face f = new Face() f.nose = new Nose() f.save()
  • 8.  one-to-one Relationship:  use the hasOne property on the owning side, e.g. Face: classAuthor { static hasOne = [book:Book] } class Book { Author author }  Note that using this property puts the foreign key on the inverse table to the previous example, so in this case the foreign key column is stored in the nose table inside a column called face_id.
  • 9.  hasOne only works with bidirectional relationships.  it's a good idea to add a unique constraint on one side of the one-to-one relationship: classAuthor { static hasOne = [book:Book] static constraints = { book unique: true } } class Book { Author author }
  • 10.  One-to-many Relationship: classAuthor { static hasMany = [books: Book] String name } class Book { String title }  In this case we have a unidirectional one-to- many. Grails will, by default, map this kind of relationship with a join table.
  • 11.  Grails will automatically inject a property of type java.util.Set into the domain class based on the hasMany setting.This can be used to iterate over the collection: def a = Author.get(1) for (book in a.books) { println book.title }
  • 12.  The default fetch strategy used by Grails is "lazy", which means that the collection will be lazily initialized on first access.  The default cascading behaviour is to cascade saves and updates, but not deletes unless a belongsTo is also specified: classAuthor { static hasMany = [books: Book] String name } class Book { static belongsTo = [author: Author] String title }
  • 13.  If you have two properties of the same type on the many side of a one-to-many you have to use mappedBy to specify which the collection is mapped: classAirport { static hasMany = [flights: Flight] static mappedBy = [flights: "departureAirport"] } class Flight { Airport departureAirport Airport destinationAirport }
  • 14.  Many-to-many Relationship:  Grails supports many-to-many relationships by defining a hasMany on both sides of the relationship and having a belongsTo on the owned side of the relationship: class Book { static belongsTo = Author static hasMany = [authors:Author] String title } classAuthor { static hasMany = [books:Book] String name }
  • 15.  Grails maps a many-to-many using a join table at the database level.The owning side of the relationship, in this case Author, takes responsibility for persisting the relationship and is the only side that can cascade saves across.
  • 16.  Relationship with the basic collection type:  As well as associations between different domain classes, GORM also supports mapping of basic collection types.  For example, the following class creates a nicknames association that is a Set of String instances: class Person { static hasMany = [nicknames: String] }
  • 17.  GORM will map an association like the above using a join table.  You can alter various aspects of how the join table is mapped using the joinTable argument: class Person { static hasMany = [nicknames: String] static mapping = { hasMany joinTable: [name: 'bunch_o_nicknames', key: 'person_id', column: 'nickname', type: "text"] } }
  • 18.  As well as association, Grails supports the notion of composition.  In this case instead of mapping classes onto separate tables a class can be "embedded" within the current table.  For example: class Person { Address homeAddress Address workAddress static embedded = ['homeAddress', 'workAddress'] } classAddress { String number String code }
  • 19.  The resulting mapping would looking like this: If you define the Address class in a separate Groovy file in the grails-app/domain directory you will also get an address table.
  • 20.  Custom mappings are defined using a static mapping block defined within your domain class: class Person { … static mapping = { version false autoTimestamp false } }
  • 21.  You can also configure global mappings in Config.groovy (or an external config file) using this setting: grails.gorm.default.mapping = { version false autoTimestamp false }
  • 22. class Person { String firstName Sting address static mapping = { version false autoTimestamp false table 'people' //Table name firstName column: 'First_Name' // column name address type:'text' } }  for the type in mapping you can create user defined types using hibernate org.hibernate.usertype Interface UserType.
  • 23.  GORM supports inheritance both from abstract base classes and concrete persistent GORM entities.  Inheritance hierarchies  Table‐per‐hierarchy:All classes map to a single table  Table‐per‐subclass: Each class maps to its own table and JOINs are used
  • 24.  For example: classContent { String author } class BlogEntry extends Content { URL url } class Book extends Content { String ISBN } class PodCast extends Content { byte[] audioStream }  In the above example we have a parent Content class and then various child classes with more specific behavior.
  • 25.  At the database levelGrails by default uses table-per-hierarchy mapping with a discriminator column called class so the parent class (Content) and its subclasses (BlogEntry, Book etc.), share the same table.  By default same table, forTable-per- hierarchy.
  • 26.  Table-per-hierarchy mapping has a down side in that you cannot have non-nullable properties with inheritance mapping.  To have two different tables for them: use table-per-hierarchy=false  To use table per subclass: ▪ tablePerHierarchy false
  • 27.  Retrieving Objects:  get(), getAll(), read()  Listing objects:  list(), listOrderBy*() methods  order, sort, offset, and max named arguments
  • 28.  Sets:  Sets of Objects  By default when you define a relationship withGORM it is a java.util.Set which is an unordered collection that cannot contain duplicates. In other words when you have: classAuthor { static hasMany = [books: Book] }
  • 29.  The books property that GORM injects is a java.util.Set. Sets guarantee uniquenes but not order, which may not be what you want. To have custom ordering you configure the Set as a SortedSet: class Author { SortedSet books static hasMany = [books: Book] }
  • 30.  In the above case a java.util.SortedSet implementation is used which means you must implement java.lang.Comparable in your Book class: class Book implements Comparable { String title Date releaseDate = new Date() int compareTo(obj) { releaseDate.compareTo(obj.releaseDate) } }
  • 31.  Lists of Objects:  To keep objects in the order which they were added and to be able to reference them by index like an array you can define your collection type as a List: classAuthor { List books static hasMany = [books: Book] }  In this case when you add new elements to the books collection the order is retained in a sequential list indexed from 0 so you can do: author.books[0] // get the first book
  • 32.  Bags of Objects:  If ordering and uniqueness aren't a concern (or if you manage these explicitly) then you can use the Hibernate Bag type to represent mapped collections.  The only change required for this is to define the collection type as a Collection:
  • 33. classAuthor { Collection books static hasMany = [books: Book] }  Since uniqueness and order aren't managed by Hibernate, adding to or removing from collections mapped as a Bag don't trigger a load of all existing instances from the database, so this approach will perform better and require less memory than using a Set or a List.
  • 34.  Maps of Objects:  If you want a simple map of string/value pairs GORM can map this with the following: classAuthor { Map books // map of ISBN:book names } def a = newAuthor() a.books = ["1590597583":"Grails Book"] a.save()  In this case the key and value of the map MUST be strings.
  • 35.  If you want a Map of objects then you can do this: class Book { Map authors static hasMany = [authors: Author] } def a = new Author(name:"Stephen King") def book = new Book() book.authors = [stephen:a] book.save()
  • 36.  CollectionTypes and Performance:  The Java Set type doesn't allow duplicates.To ensure uniqueness when adding an entry to a Set association Hibernate has to load the entire associations from the database.  If you have a large numbers of entries in the association this can be costly in terms of performance.
  • 37.  The same behavior is required for List types, since Hibernate needs to load the entire association to maintain order.Therefore it is recommended that if you anticipate a large numbers of records in the association that you make the association bidirectional so that the link can be created on the inverse side.
  • 38.  For example consider the following code: def book = new Book(title:"New Grails Book") def author =Author.get(1) book.author = author book.save()  In this example the association link is being created by the child (Book) and hence it is not necessary to manipulate the collectiodirectly resulting in fewer queries and more efficient code.
  • 39.  Given an Author with a large number of associated Book instances if you were to write code like the following you would see an impact on performance: def book = new Book(title:"New Grails Book") def author =Author.get(1) author.addToBooks(book) author.save()  You could also model the collection as a Hibernate Bag as described above.
  • 40.  By default Lazy fetching, object will be loaded only when it will be accessed.  Lazy can be set to false to enable eager fetching: classAirport { String name static hasMany = [flights: Flight] static mapping = { flights lazy: false } }  In this case the flights association will be loaded at the same time as its Airport instance
  • 41.  Although eager fetching is appropriate for some cases, it is not always desirable.  If you made everything eager you could quite possibly load your entire database into memory resulting in performance and memory problems.  An alternative to eager fetching is to use batch fetching.You can configure Hibernate to lazily fetch results in "batches".
  • 42.  For example: classAirport { String name static hasMany = [flights: Flight] static mapping = { flights batchSize: 10 } }  In this case, due to the batchSize argument, when you iterate over the flights association, Hibernate will fetch results in batches of 10.
  • 43.  For example:  If you had an Airport that had 30 flights,  if you didn't configure batch fetching you would get 1 query to fetch the Airport and then 30  queries to fetch each flight:  With batch fetching you get 1 query to fetch the Airport and 3 queries to fetch each Flight in batches of 10.
  • 44.  In other words: batch fetching is an optimization of the lazyfetching strategy.  Batch fetching can also be configured at the class level as follows: class Flight { … static mapping = { batchSize 10 } }
  • 45.  Optimistic Locking:  By default GORM classes are configured for optimistic locking.  Optimistic locking is a feature of Hibernate which involves storing a version value in a special version column in the database that is incremented after each update.
  • 46.  The version column gets read into a version property that contains the current versioned state of persistent instance which you can access: def airport = Airport.get(10) println airport.version  When you perform updates Hibernate will automatically check the version property against the version column in the database and if they differ will throw a StaleObjectException.This will rollback the transaction if one is active.  The version will only be updated after flushing the session.
  • 47.  Dealing with the locking through exception handling: def airport = Airport.get(10) try { airport.name = "Heathrow" airport.save(flush: true) } catch (org.springframework.dao.OptimisticLockingFailureException e) { // deal with exception }  The way you deal with the exception depends on the application.You could attempt a programmatic merge of the data or go back to the user and ask them to resolve the conflict.
  • 48.  Pessimistic Locking:  Pessimistic locking is equivalent to doing a SQL "SELECT * FOR UPDATE" statement and locking a row in the database.  This has the implication that other read operations will be blocking until the lock is released.
  • 49.  In Grails pessimistic locking is performed on an existing instance with the lock method: def airport = Airport.get(10) airport.lock() // lock for update airport.name = "Heathrow" airport.save()  Grails will automatically deal with releasing the lock for you once the transaction has been committed.  In the above case what we are doing is "upgrading" from a regular SELECT to a SELECT..FOR UPDATE and another thread could still have updated the record in between the call to get() and the call to lock().
  • 50.  To get around this problem you can use the static lock method that takes an id just like get: def airport = Airport.lock(10) // lock for update airport.name = "Heathrow" airport.save()
  • 51.  Using pessimistinc locking in dynamic finders and criteria:  As well as the lock method you can also obtain a pessimistic locking using queries.  For example using a dynamic finder: def airport = Airport.findByName("Heathrow", [lock: true])  Or using criteria: def airport = Airport.createCriteria().get { eq('name', 'Heathrow') lock true }
  • 52.  You can use the isDirty method to check if any field has been modified: def airport = Airport.get(10) assert !airport.isDirty() airport.properties = params if (airport.isDirty()) { // do something based on changed state }  isDirty() does not currently check collection associations, but it does check all other persistent properties and associations.
  • 53.  You can also check if individual fields have been modified: def airport = Airport.get(10) assert !airport.isDirty() airport.properties = params if (airport.isDirty('name')) { // do something based on changed name }
  • 54.  getDirtyPropertyNames:  You can use the getDirtyPropertyNames method to retrieve the names of modified fields; this may be empty but will not be null: def airport = Airport.get(10) assert !airport.isDirty() airport.properties = params def modifiedFieldNames = airport.getDirtyPropertyNames() for (fieldName in modifiedFieldNames) { // do something based on changed value }
  • 55.  getPersistentValue:  You can use the getPersistentValue method to retrieve the value of a modified field: def airport = Airport.get(10) assert !airport.isDirty() airport.properties = params def modifiedFieldNames = airport.getDirtyPropertyNames() for (fieldName in modifiedFieldNames) { def currentValue = airport."$fieldName" def originalValue = airport.getPersistentValue(fieldName) if (currentValue != originalValue) { // do something based on changed value } }
  • 56.  Use property names of the class  Support for many expressions in finder method def book = Book.findByTitle("The Stand") book = Book.findByTitleLike("Harry Pot%")  Like is comparator, due to the Like comparator, above finder is equivalent to a SQL like expression.
  • 57.  The possible comparators include: InList In the list of given values LessThan less than a given value LessThanEquals less than or equal a give value GreaterThan greater than a given value GreaterThanEquals greater than or equal a given value Like Equivalent to a SQL like expression Ilike Similar to a Like, except case insensitive NotEqual Negates equality Between Between two values (requires two arguments) IsNotNull Not a null value (doesn't take an argument) IsNull Is a null value (doesn't take an argument)
  • 58.  Between, IsNotNull and IsNull require different numbers of method arguments compared to the rest, as demonstrated in the following example: def now = new Date() def lastWeek = now - 7 def book = Book.findByReleaseDateBetween(lastWeek, now) books = Book.findAllByReleaseDateIsNull() books = Book.findAllByReleaseDateIsNotNull()
  • 59.  Boolean logic (AND/OR):  Method expressions can also use a boolean operator to combine two or more criteria: def books = Book.findAllByTitleLikeAndReleaseDateGreaterThan( "%Java%", new Date() - 30)  In this case we're using And in the middle of the query to make sure both conditions are satisfied, but you could equally use Or: def books = Book.findAllByTitleLikeOrReleaseDateGreaterThan( "%Java%", new Date() - 30)
  • 60.  Built on Hibernate’s CriteriaAPI  Groovy builder is used to build up the criteria ▪ Hierarchy of method calls and closures for building tree‐like structures  Each domain class has a createCriteria() method ▪ Call get, list, scroll, or count on criteria ▪ The criteria builder is used to restrict the query  Supports associations and projections
  • 61.  Some Criteria queries: def c = Account.createCriteria() def results = c.list { like("holderFirstName", "Fred%") and { between("balance", 500, 1000) eq("branch", "London") } maxResults(10) order("holderLastName", "desc") }
  • 62.  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 (caseinsensitive) A version of eq that supports an optional 3rd Map parameter to specify that the query be caseinsensitive. eq("branch", "london", [ignoreCase: true]) eqProperty Where one property must equal another eqProperty("lastTx", "firstTx")
  • 63. Node Description Example gt Where a property is greater than a particular value gt("balance",1000) gtProperty Where a 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 a 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 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])}
  • 64. isEmpty Where a collection property is empty isEmpty("transactions") isNotEmpty Where a collection property is not empty isNotEmpty("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 a 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 a one property must be less than or equal to another leProperty("balance", "overdraft")
  • 65. 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)
  • 66. 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"
  • 67.  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
  • 68.  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" } }
  • 69.  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")
  • 70. 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()
  • 71.  Criteria can be written as: def query = { and { eq('survey', survey) eq('user',user) } } FormSubmission.createCriteria().list(query) or FormSubmission.createCriteria().list{ and { eq('survey', survey) eq('user',user) } }
  • 72.  Adding SQLRestrictions in a criteria:  Find all the users with first name, lastname dob, but their status should not be null or test_user, and their role should be ROLE_USER in userrole table.  User UserRole classes are created by springSecurityPlugin:
  • 73. Role userRole = Role.findByAuthority('ROLE_USER'); UserList = User.createCriteria().list{ and{ if(params.firstName){ ilike('firstName',params.firstName+'%') } if(params.lastName){ ilike('lastName', params.lastName+'%') } if(birthDate){ eq('birth', birthDate) } sqlRestriction("({alias}.status IS NULLOR CAST({alias}.statusAS nvarchar) != 'test_user')AND ${userRole.id} in (Select ur.role_id from user_role ur where ur.user_id={alias}.id)") } if (!params.offset) { params.offset = 0 } if (!params.max) { params.max = 10 } maxResults(params.max.toInteger()) firstResult(params.offset.toInteger()) }
  • 74.  Support for HibernateQuery Language:  find(hql), findAll(hql), and executeQuery(hql) for queries  executeUpdate(hql) for DML‐style opera3ons (sets of updates or deletes)  Support for positional and named parameters EAVEntity.executeQuery("SELECT e.id FROM EAVEntity eWHERE e.initialEntryBy=:entryFor AND e.attribute=:attrId", [entryFor:''+entryFor+'', attrId: this.parentAttribute])
  • 75.  // 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])
  • 76.  // 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'])  // same as previous Account.executeQuery("select distinct a.number from Account a "+“ where a.branch = :branch", [branch: 'London'], [max: 10, offset: 5])
  • 77.  // 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])
  • 78.  // 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])
  • 79.  The executeQuery method allows the execution of arbitrary HQL queries.  HQL queries can return domain class instances, or Arrays of specified data when the query selects individual fields or calculated values.
  • 80.  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)  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
  • 81.  Support forWriting native queries:  Defining new SQL instance: creating a new sql instance, basically it will create a new instance of the connection: Sql sql = Sql.newInstance(dataSource)  Then we can execute the methods on the sql. sql.rows("SELECT id FROM eavchoice_entity_valueWHERE entity_id=:id",[id:newEntityId]); String entityInsertQuery = "insert into eaventity (version, attribute_id, initial_entry_by)VALUES (0, $attributeId, '$entryFor')"; def newEntity = sql.executeInsert(entityInsertQuery); sql.close()
  • 82.  Using ExplicitTransaction with Native sql queries: ▪ // Creating sql instance Sql sql = Sql.newInstance(dataSource) ▪ // Instantiating transaction manager DataSourceTransactionManager txm = new DataSourceTransactionManager(dataSource)
  • 83.  // instantiating transaction through transaction manager def status = txm.getTransaction( new DefaultTransactionDefinition() ) try{ /* Write sql queries */ sql.close() txm.commit(status) }catch(Exception e){ log.error("Exception in saving data", e) //Transaction roll back txm.rollback(status) }finally(){ sql.close() //Cleanup resources after transaction completion. txm.cleanupAfterCompletion( status ) }
  • 84.  Where Queries:  The where method, introduced in Grails 2.0, builds on the support for Detached Criteria by providing an enhanced, compile-time checked query DSL for common queries.  The where method is more flexible than dynamic finders, less verbose than criteria and provides a powerful mechanism to compose queries.
  • 85.  Basic Querying:  The where method accepts a closure that looks very similar to Groovy's regular collection methods.  The closure should define the logical criteria in regular Groovy syntax, for example: def query = Person.where { firstName == "Bart" } Person bart = query.find()
  • 86.  The returned object is a DetachedCriteria instance, which means it is not associated with any particular database connection or session.  This means you can use the where method to define common queries at the class level: class Person { static simpsons = where { lastName == "Simpson" } … }
  • 87.  Query execution is lazy and only happens upon usage of the DetachedCriteria instance.  If you want to execute a where-style query immediately there are variations of the findAll and find methods to accomplish this: def results = Person.findAll { lastName == "Simpson" } def results = Person.findAll(sort:"firstName") { lastName == "Simpson" } Person p = Person.find { firstName == "Bart" }
  • 88.  Each Groovy operator maps onto a regular criteria method.  The following table provides a map of Groovy operators to methods: Operator Criteria Method Description == eq Equal to != ne Not Equal to > gt Greater than < lt Less than >= ge Greater than or equal to <= le Less than or equal to in inList Contained within the given list ==~ like Like a given string =~ ilike Case insensitive like
  • 89.  It is possible use regular Groovy comparison operators and logic to formulate complex queries: def query = Person.where { (lastName != "Simpson" && firstName != "Fred") || (firstName == "Bart" && age > 9) } def results = query.list(sort:"firstName")  The Groovy regex matching operators map onto like and ilike queries unless the expression on the right hand side is a Pattern object, in which case they map onto an rlike query: def query = Person.where { firstName ==~ ~/B.+/ }  ** Note that rlike queries are only supported if the underlying database supports regular expressions
  • 90.  A between criteria query can be done by combining the in keyword with a range: def query = Person.where { age in 18..65 }  Finally, you can do isNull and isNotNull style queries by using null with regular comparison operators: def query = Person.where { middleName == null }
  • 91.  Query Composition:  Since the return value of the where method is a DetachedCriteria instance you can compose new queries from the original query: def query = Person.where { lastName == "Simpson" } def bartQuery = query.where { firstName == "Bart" } Person p = bartQuery.find()
  • 92.  Note that you cannot pass a closure defined as a variable into the where method unless it has been explicitly cast to a DetachedCriteria instance.  In other words the following will produce an error: def callable = { lastName == "Simpson" } def query = Person.where(callable)
  • 93.  The above must be written as follows: import grails.gorm.DetachedCriteria def callable = { lastName == "Simpson" } as DetachedCriteria<Person> def query = Person.where(callable)  As you can see the closure definition is cast (using the Groovy as keyword) to a DetachedCriteria instance targeted at the Person class.
  • 94.  Conjunction, Disjunction and Negation:  As mentioned previously you can combine regular Groovy logical operators (|| and &&) to form conjunctions and disjunctions: def query = Person.where { (lastName != "Simpson" && firstName != "Fred") || (firstName == "Bart" && age > 9) }  You can also negate a logical comparison using !: def query= Person.where { firstName == "Fred" && !(lastName == 'Simpson') }
  • 95.  Property Comparison Queries:  If you use a property name on both the left hand and right side of a comparison expression then the appropriate property comparison criteria is automatically used: def query = Person.where { firstName == lastName }
  • 96.  The following table described how each comparison operator maps onto each criteria property comparison method: Operator Criteria Method Description == eqProperty Equal to != neProperty Not equal to > gtProperty Greater than < ltProperty Less than >= geProperty Greater than or equal to <= leProperty Less than or equal to
  • 97.  Querying Associations:  Associations can be queried by using the dot operator to specify the property name of the association to be queried: def query = Pet.where { owner.firstName == "Joe" || owner.firstName == "Fred" }
  • 98.  You can group multiple criterion inside a closure method call where the name of the method matches the association name: def query = Person.where { pets { name == "Jack" || name == "Joe" } }  This technique can be combined with other top- level criteria: def query = Person.where { pets { name == "Jack" } || firstName == "Ed" }
  • 99.  For collection associations it is possible to apply queries to the size of the collection: def query = Person.where { pets.size() == 2 }
  • 100.  Subqueries:  It is possible to execute subqueries within where queries. For example to find all the people older than the average age the following query can be used: final query = Person.where { age > avg(age) }
  • 101.  The following table lists the possible subqueries: Method Description avg The average of all values sum The sum of all values max The maximum value min The minimum value count The count of all values property Retrieves a property of the resulting entities
  • 102.  You can apply additional criteria to any subquery by using the of method and passing in a closure containing the criteria: def query = Person.where { age > avg(age).of { lastName == "Simpson" } && firstName == "Homer" }  Since the property subquery returns multiple results, the criterion used compares all results.  For example the following query will find all people younger than people with the surname "Simpson": Person.where { age < property(age).of { lastName == "Simpson" } }
  • 103.  There are several functions available to you within the context of a query.These are summarized in the table below: Method Description second The second of a date property minute The minute of a date property hour The hour of a date property day The day of the month of a date property month The month of a date property year The year of a date property upper Converts a string property to upper case lower Converts a string property to lower case length The length of a string property trim Trims a string property
  • 104.  **Currently functions can only be applied to properties or associations of domain classes.You cannot, for example, use a function on a result of a subquery.  For example the following query can be used to find all pet's born in 2011: def query = Pet.where { year(birthDate) == 2011 }  You can also apply functions to associations: def query = Person.where { year(pets.birthDate) == 2009 }
  • 105.  Batch Updates and Deletes: ▪ Since each where method call returns a DetachedCriteria instance, you can use where queries to execute batch operations such as batch updates and deletes. ▪ For example, the following query will update all people with the surname "Simpson" to have the surname "Bloggs": def query = Person.where { lastName == 'Simpson' } int total = query.updateAll(lastName:"Bloggs")
  • 106.  **Note that one limitation with regards to batch operations is that join queries (queries that query associations) are not allowed.  To batch delete records you can use the deleteAll method: def query = Person.where { lastName == 'Simpson' } int total = query.deleteAll()