Last updated by admin 3 years ago
Grails Object Relational Mapping (GORM)
??
Domain classes are core to any business application. They hold state about business processes and hopefully also implement behavior. They are linked together through relationships, either one-to-one or one-to-many.GORM is Grails' object relational mapping (ORM) implementation. Under the hood it uses Hibernate 3 (an extremely popular and flexible open source ORM solution) but because of the dynamic nature of Groovy, the fact that it supports both static and dynamic typing and the convention of Grails there is less configuration involved in creating Grails domain classes.You can also write Grails domain class in Java see the section on Hibernate Integration for how to write Grails domain classes in Java but still use dynamic persistent methods.Creating a Domain Class
A domain class in Grails is essentially a normal Groovy class with 2 key characteristics: An "id" property and a "version" property:class Book {
@Property Long id
@Property Long version @Property String title
}grails create-domain-class
Creating Relationships
Defining a one-to-many relationship is a simple matter of defining a property of type Set and adding the mapping to the "relatesToMany" map:class Author {
@Property Long id
@Property Long version @Property relatesToMany = [ books : Book ] @Property String name
@Property Set books = new HashSet()
}class Book {
@Property Long id
@Property Long version @Property Author author
@Property String title
}class Book {
@Property Long id
@Property Long version @Property belongsTo = Author @Property Author author
@Property String title
}@Property belongsTo = [Author,Publisher]
- an owner can have belongings
- belongings use the 'belongsTo' property to refer to their owner(s)
- if an owner dies, all his belongings vanish.
Relationship Summary
Here is a tabular summary of possible relationships between two classes A and B.Relationships may be unidirectional (->) or bidirectional (<->) and have cardinalities one-to-one (1:1), one-to-many (1:m), many-to-one (m:1), and many-to-many (n:m). The owner is marked as bold. || A:B || unidirectional || bidirectional || | 1:1 | A -> B | A <-> B ; B.belongsTo = [A] | | 1:m | A -> Set ; A.relatesToMany= [B] | A -> Set ; A.relatesToMany = [B]; B -> A (*) | | m:1 | A -> B | A -> B ; B -> Set ; B.relatesToMany = [A] (*g) | | n:m | n/a | n/a | (*) no {{belongsTo}} needed since in one-to-many always {{one}} is the owner. (g) opposite of ()Optional and Transient properties
By default all properties are both persistent and required, to change that you can define List properties called "optionals" and "transients":class Book {
@Property Long id
@Property Long version @Property optionals = [ "releaseDate" ]
@Property transients = [ "digitalCopy" ] @Property Author author
@Property String title
@Property String author
@Property Date releaseDate
@Property File digitalCopy
}CRUD Operations
Grails domain classes use dynamic persistent methods to facilitate CRUD (Create/Read/Update/Delete) operations on persistent classes:Create
To create entries in the database, domain class instances support a "save" method which cascades to the instance relationships. In the example below we only call "save" on the author and both the Author and Book instances are persisted:def a = new Author(name:"Stephen King") def b = new Book(title:"The Shining",author:b) a.books.add(b)// persist a.save()
def addBook(book) {
if(!books)books = new HashSet()
book.author = this
books.add(book)
return this
}def a = new Author(name:"Stephen King") a.addBook(new Book(title:"The Shining")) .addBook(new Book(title:"IT")) .save()
Read
Grails supports a number of ways of retrieving domain class instances, for more detail on querying see the section on ##Domain Class Querying, however to retrieve an instance if the "id" is known you can use the "get" static method:Book.get(1)
Book.findAll() // retrieve all
Book.list(10) // lists first 10 instances
Book.listOrderByTitle() // lists all the instances ordered by the "title" propertyUpdate
The symantics of updating differ from that of saving a domain class. It is possible to update without explicitly calling "save" with the changes automatically being persisted if no exceptions occur:def b = Book.get(1)
b.releaseDate = new Date()def b = Book.get(1) b.title = null // can't have a null title b.save() // won't save as fails to validate
def b = Book.get(1) b.publisher = "Print It"if(!b.validate()) { b.publisher = Publisher.DEFAULT }
b.validate(true)def b = Book.get(1)
b.title = "A New Title"// something happenedd to change your mind
b.discard()Delete
Domain class instances can be removed from the database by using the "delete" instance method:def b = Book.get(1) b.delete()
Domain Class Querying
Querying with dynamic methods
There are several ways to query for domain class instances, one of them being via Grails dynamic methods, from more details see DomainClass Dynamic Methods:def results = Book.findByTitle("The Stand")results = Book.findByTitleLike("Harry Pot%") results = Book.findByReleaseDateBetween( firstDate, secondDate ) results = Book.findByReleaseDateGreaterThan( someDate ) results = Book.findByTitleLikeOrReleaseDateLessThan( "%Something%", someDate )// find by relationship results = Book.findAllByAuthor( Author.get(1) )
Querying by example
Just pass an example of the domain object you would like to find to the find() method.def b = Book.find( new Book(title:'The Shining') )Querying with a criteria builder
For more advanced queries or querying across objects graphs you can use Criteria (for a full reference see the section on Builders):def c = Book.createCriteria()
def results = c {
like("author.name", "Stephen%")
between("releaseDate", firstDate, secondDate )
}Querying with HQL queries
Otherwise, as Grails uses Hibernate internally you can use an HQL query:def results = Book.find("from Book as b where b.title like 'Lord of the%'")def results = Book.find("from Book as b where b.title like ?", ["The Shi%"])



