JAVA exPress logo Published on JAVA exPress (http://www.javaexpress.pl)

GORM – Grails Object Relational Mapping

Mateusz Mrozewski

Issue 6 (2009-12-09)

In this article I would like to present some basic information on GORM (Grails Object Relational Mapping) and further issues of this topic. After reading the article you will know how the persistence layer works in Grails.

Let's begin

GORM, the persistence layer in Grails is implemented as object relational mapping. Under its name we will find Hibernate or we can use is in a direct way.

Object relational mapping is implemented in Grails in so called Domain class. It is known also as entity. Created domain class (in the command line or created by NetBeans) in a simple case is only an empty class, to which we add attributes we want it to contain:

    class Person {
        String firstname
        String lastname
    }

After creating such domain class and starting our project (with default settings) in NetBeans, a Hypersonic data base will be set up and a new Person table will be created. It will have 4 columns: firstname, lastname, id and version. Grails by default generate identifiers and control version (in the most appropriate way for the certain data base).

The basic operations (CRUD) are to be done in the following way:

    // Creating new record CREATE
    def p1 = new Person(firstname:"Mateusz", lastname:"Mrozewski");
    p1.save()
     
    // Reading record READ
    // tu korzystamy z automatycznie wygenerowanego id
    def p2 = Person.get(1) 
     
    // UPDATE
    // we modify the record read before
    p2.firstname = "Krzysztof" 
    p2.save(); 
     
    // DELETE
    // we delete the record read before
    p2.delete() 

   

As we can see doing basic operations is extremely easy.

Associations

GORM becomes more interesting when we add associations. But is also solved in very clear way. Here are some examples:

    // One-to-one unidirectional
    // Having reference to car we can get its engine, but not opposite
    Class Car {
        Engine engine
    } 
     
    Class Engine {}
     
    // One-to-one bidirectional
    // Having reference to car we can get its engine, also opposite
    Class Car {
        Engine engine
    }
     
    Class Engine {
        Car car
    } 

   

In case of both relations above the operations are not cascaded. This means that if delete car, its engine will remain. It looks similar in case of saving changes, creating new record, or updating. We don't have to do it manually for both classes.

    // One-to-one unidirectional
    // Having reference to car we can get its engine, but not opposite
    Class Car {
        Engine engine
    } 
     
    Class Engine {
        static belongsTo = Car
    }
     
    // One-to-one bidirectional
    // Having reference to car we can get its engine, also opposite
    Class Car {
        Engine engine
    }
     
    Class Engine {
        static belongsTo = [car:Car]
    } 

   

As we can see, cascading can be done through belongsTo property. What we should focus on is the difference in declaration of this property in one way and two way relation.

Since the version 1.2-M4 of Grails we have yet another possibility of declaration of relation one-to-one:

    class Car {
        static hasOne = [engine:Engine]
    }

    class Engine {
        Car car
    }

The difference in comparison to the previous examples is that foreign key will be placed in the engine table, and not in the car table.

The relation of bigger multiplicity can be created by using the hasMany property. Using it in both sites of relation we get many to many relation. Just as in one to one cases, force cascading we should use belongsTo relation. The example is the following:

    // One-to-many unidirectional
    class Car {
        static hasMany = [wheels:Wheel]
    }
     
    class Wheel {
    }

   

Because of one to many relation we have to remember about a few things: 

In case of many to many relation we use hasMany property at both sides:

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

   

Also in this case we can use belongsTo property. The documentation mentions that scaffolding does not support this type of relation.

Grails by default applies the Set collection in case of the relation bigger that one. Default behaviour can be overwritten by using collection of our choise, so any implementation of Set, List or Map.

Strategies of inheritance

Grails supports two strategies of inheritance: table-per-hierarchy and table-per-subclass. This is at least the information in the official documentation. As far as we know on the lower layer of Grails we can find Hibernate, which supports also the table-per-concrete-class strategy, so perhaps we could use it in Grails as well.

What are really the strategies inheritance? It is a proud sounding name, but in fact it is not so complex. Let's imagine one domain class extends another domain class, e.g.:

    class Person {
        String name
        String surname
    }
     
    class Employee extends Person {
        String taxpayerIdNumber
    }

   

The strategy inheritance defines how such structure will be presented in the data base. As long as we didn't use inheritance, each domain class used to have its own table. In this case if we apply table-per-hierarchy strategy (by default) all the classes from the hierarchy will be put in the same table. This table will look like the following one:

    CREATE TABLE `person` (
        `id` bigint(20) NOT NULL auto_increment,
        `version` bigint(20) NOT NULL,
        `name` varchar(255) NOT NULL,
        `surname` varchar(255) NOT NULL,
        `class` varchar(255) NOT NULL,
        `taxpayer_id_number` varchar(255) NULL,   PRIMARY KEY  (`id`)
    );

As we can see the table have columns name and surname declared in Person class and the field taxpayer_id_number from the Employee class. Additionally it contains the identifier automatically created by Grails (in my case auto_increment as I use MySQL), the column version to version control of records, and the column class which enables to determine whether the line represents the person or the employee. The advantage of such solution is having everything you need in one table (the question of optimalization – you don't need any joining operations). The disadvantage is that our application enables to hire an employee with no permit – the column taxpayer_id_number has to be null (because otherwise we would like to add the person who is not an employee and doesn't have taxpayer id number).

Another available strategy is table-per-subclass. In this case each subclass will have an additional table which will keep only additional fields. Inherited fields will be kept in the table of base class. How to do that? Simply add a small piece of the code in the superior class:

    class Person {
        String name
        String surname
     
        static mapping = {
            tablePerHierarchy false
        }
    }
     
    class Employee extends Person {
        String taxpayerIdNumber
    }

   

In this case the table person will be created, including fields: id, version, name and surname. The second table is employee, which will include fields: id (covering the table person) and taxpayer_id_number. The disadvantage of this/such solution is the need to join always when we would like to get the employee record. In return we can force taxpayer id number on the level of the database.

Nested domain classes

There is no extended documentation on this topic but I don't think there is much to explain. The point is that we can nest the domain class in another domain class. From the point of view of the code we still declare two classes, but we indicate that a certain property is nested class, e.g.:

    class Car {
        Engine engine
        static embedded = ['engine']
    }
     
    class Engine {
        String type
    }

   

From such declaration we will get one table car which will have fields id, version and engine_type. It enables to nicely separate object model and optimalyze queries at the same time. Instead of two queries or one with joining we simply have one. We have to remember that both classes should be declared in Car.groovy file. If we move class Engine to a separate file, a separate table for this class will be generated.

Opimistic and Pessimistic Locking

Locking is a way to protect against concurrent changes. Generally there are two approaches: the optimistic, which assumes that concurrent changes will rather not appear (checking is done at the end of the operation/transaction), and pessimistic, which assumes that concurrent changes are so common that it is better to preempt record before carrying out any changes. These are commonly used approaches, not only in Grails (and only in web frameworks).  

Optimistic locking uses record version (Grails, or actually Hibernate does it for us). Each domain class has automatically generated attribute version, which is incremented with every update. If, while saving the record, GORM detects that in the meantime the version has been changed by another transaction, our transaction will be rollbacked and the exception StaleObjectException will be thrown. It depends on us how we will do it: we can overwrite changes or resign from saving it, and ask the user to do the changes on the current data again.

Pessimistic locking, on the other hand, works using SELECT ... FOR UPDATE operation. Carrying out such operation on the data base causes locking the record for other transactions (on the data base level). Other transactions, which will try to get the same record will be suspended and will wait for its unlocking. We should remember that it is data base dependent mechanism and such the documentation says, HSQLDB provided with Grails does not support it. And this is how it looks like in the code:

    def car = Car.get(1)
    // here different thread can get the same record and locking is useless
    car.lock() // here we lock the record
    car.model = "Audi"
    car.save()
     
    // different version solving this problem
    def car = Car.lock(1)
    car.model = "Audi"
    car.save()

   

We also can lock right away while making queries. Unlocking happens (locks are unlocked) when a transaction is approved or undone.

Getting data

GORM enables to make queries on several ways. Among them we can rank the basic operating methods on domain classes, dynamic finders (find* methods), criteria which allow to bulid queries similar to JaQu, or using good old HQL.

Methods of domain classes

The following fragment of the code will illustrate in the best way what kind of methods we can call:

    // List all persons
    def persons = Person.list()
    // Get perosn with id=3
    def person = Person.get(3)
    // Get person with id 3,4,5
    def persons = Person.getAll(3, 4, 5)
    // Get 10 person with offset 100, sorting by surname malejąco
    def persons = Person.list(max:10, offset:100, sort:"lastname", order:"desc") 

   

For method list() we can additionally define the quantity of returned records, from which record we should begin, sorting according to the direction, and also in what way to get associations (eager/lazy). Method get() simply gets the record with given id, and getAll() gets the records with given id. When any of them does not exist, the list of results will contain null.

Dynamic finders

Dynamic finders are methods created dynamically in the runtime enviroment, on the basis of the class property.

    class Person {
        String firstname
        String lastname
        Date dateOfBirth
    }
     
    def p1 = Person.findByFirstname("Mateusz")
    def p2 = Person.findByLastname("Mrozewski")
    def p3 = Person.findByFirstnameAndLastnameLike("Mateusz", "M%")
    def p4 = Person.findByDateOfBirthIsNull()

   

The above mentioned methods are only some possible examples. We can call such methods for every property. Just like in the example finding person p3, we can join conditions for any two properties with operator AND or OR (the maximum is two – for bigger number we should use criteria or HQL). Two types of methods are findBy*, which returns the first result record, and findAllBy*, which return all the matching results. The permitted operations are:

This type of queries can be also used for associations. For these queries we can also add such parameters as in list() method. Great, isn't it? Personally I think that by using already two parameters it begin to be not clear and it is much easier to write and analyze criteria, but for simple queries it is by all means interesting solution.

But wait a moment! Where all the methods did come from? After all we didn't inherit and we didn't implement anything. Here, with help comes the dynamism of Groovy and the fact how it was used in Grails. Specifically it is about using meta classes and their property methodMissing. In the book The Definitive Guide to Grails, in the supplement concerning Groovy we can find surprisingly easy example of implementation of dynamic finder.

Criteria

Criteria are the way to build complex queries through Groovy syntax. What is used here specifically is the conception of builders.

However what is interesting for us is how does it look like in the code. Here is some small excerpt from the documentation:

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

In this example the criteria for domain class were created. Then we extended it by further conditions – perhaps this simple example illustrates quite good what are the possibilities of criteria. 

What can be done in such criteria:

I'm not listing here all the possibilities because there are plenty of them, and everything is in Javadocs. But at least this short list shows how many possibilities we have. GORM is not only CRUD.

HQL

In GORM we can use HQL (Hibernate Query Language). It is query language very similar to SQL. However, we don't operate on tables but on entities (domain classes). We can use three methods which can be called on our domain class:

Here are some examples:

    // Find first person named Mateusz
    def person = Person.find("from Person as p where p.firstname = ?",
            ['Mateusz'])
    // Find all persons named Mateusz and surnamed na M
    def results = Person.findAll(
            "from Person as p where p.firstname = :firstname
            and p.lastname like :lastname",
            [firstname:'Mateusz', lastname:'M%'])

   

What is crucial is to get to know the chapter from Hibernate documentation about HQL. 

Events and timestamps

Very interesting function in GORM are events. Events are closures called in the right moment of life cycle of domain class entity. We can use it e.g. to save the last update date, create entity, save log track after deleting entity etc. There are the following types of events:

And here is some example:

    class Person {
       Date dateCreated
       Date lastUpdated
       Date loadTime
     
       def beforeInsert = {
          dateCreated = Date()
       }
       def beforeUpdate = {
           lastUpdated = new Date()
       }
       def onLoad = {
           loadTime = new Date()
       }
    }

 

In this example we extended our domain class by saving updates in the date base, creation date and setting loading time of the record. When it comes to creation and update date, GORM enables some simplification: we just need to declare in the domain class the lastUpdated and dateCreated property, and they will be automatically set to right values (using convention not only we don't have to configure but also create code).

Mapping

Another feature of GORM is its own mapping of tables. Own mapping enables to define independently the names of tables and columns. It is extremely useful when we have to adapt to the convention accepted by the company, or when we write code for existing data base. In my opinion this part requires the least additional descriptions or discussion. More on this topic we can read obviously in the documentation.

I would like only to add that we can also influence on how the identifiers are generated (by default GORM uses the most appropriate one for the data base). Moreover, we can influence the indexes which will be generated.

To illustrate the possibilities, here is some example:

    class Person {
      String firstName
      static mapping = {
          table 'people'
          firstName column:'First_Name'
      }
    }

Cache

At the lower layer of GORM there is Hibernate, so for sure there is second-level cache mechanism from this library. We can enable cache in DataSource.groovy configuration file (it is enabled by default after generating project). Just like in Hibernate, in cache we can save entities or queries results. If a certain domain class is to be saved in cache, we define it in the domain class itself.

    class Person {
        static mapping = {
            cache true
        }
    }

   

We can also cache associations. One of several caches can be set up. It influences the efficiency of our memory, and this results from the strategy of data base service and the acceptable risk concerning concurrent modifications:

Contraints

Grails contains build-in mechanism of data validation. It enables very easy and declarative defining which of the properties can get certain values. Why is it important from GORM perspective? Because it can influence on how the data base schema will be generated. I really liked that we automatically get security also on the data base level, and only on the level of application.

To set contraints in domain class we use contraints section:

    class Task {
        String name
        String description

        static constraints = {
            description(maxSize:1000)
        }
    }

Summary

As we can see the layer of persistence is very extended in Grails. It is quite flexible and has a lof of functions. If someone doesn't like GORM in some way, they can always use Hibernate directly, use plugin for JPA or directly connect with the data base (JDBC or GroovySQL package). Nevertheless in my opinion GORM will satisfy most of the users.

Source: http://www.javaexpress.pl/article/show/GORM_%E2%80%93_Grails_Object_Relational_Mapping