Let's take a look at just how easy it is to use the Grails ORM DSL. For our example we will work with the tried and true Book and Publisher classes but with legacy tables in an Oracle 10g database.
Here's our domain classes in Grails:
class Publisher {
String name
String city
static hasMany = [books : Book]
}
class Book {
String title
String author
Integer pages
Publisher publisher
static belongsTo = Publisher
}
and here's the legacy tables we have to work with:
TABLE PUB01
Column Name Data Type
ID_PUB_PK NUMBER
PUB_NM VARCHAR(100)
PUB_CTY VARCHAR(100)
SEQUENCE ID_PUB_PK_SEQ
TABLE BK01
Column Name Date Type
ID_BK_PK NUMBER
BK_TITLE VARCHAR2(100)
BK_AUTHOR VARCHAR2(100)
BK_PGS NUMBER
ID_PUB_FK NUMBER
SEQUENCE ID_BK_PK_SEQ
Now let's map our Publisher class to the PUB01 table:
class Publisher {
String name
String city
static hasMany = [books : Book]
static mapping = {
table 'PUB01'
columns{
id column: 'ID_PUB_PK'
name column: 'PUB_NM'
city column: 'PUB_CTY'
}
id generator:'sequence', params:[sequence:'ID_PUB_PK_SEQ']
}
}
Let's look at what we did here. We created a static block called 'mapping'. Inside the mapping block we first define the table for this class (note that the table name and all column names are in quotes) then we create a nested block called columns. In the columns block we list each property, a space, then column: 'column name'. Using the word 'column' on each line might seem redundant but there are other attributes of a property that can be set in the columns block so when you are setting the column you have to be specific. After the columns block we have the id generation scheme, which we'll discuss in a bit.
Now we'll modify our Book class and discuss one interesting thing there:
class Book {
String title
String author
Integer pages
Publisher publisher
static belongsTo = Publisher
static mapping = {
table 'BK01'
columns{
id column: 'ID_BK_PK'
title column: 'BK_TITLE'
author column: 'BK_AUTHOR'
pages column: 'BK_PGS'
publisher column: 'ID_PUB_FK'
}
id generator: 'sequence', params:[sequence:'ID_BK_PK_SEQ']
}
}
You'll notice that this was pretty much the same thing we did with Publisher. The one difference is the way that we mapped the relationship. The publisher property which is of type Publisher is mapped using the foreign key for the Publisher table, 'ID_PUB_FK'
Now let's talk about id generators. In Grails you can use any id generation scheme supported by Hibernate. To do this with the ORM DSL you basically call an id method and pass it a map. The first key in the map is the word generator and the first value is the name of the generator class, such as 'hilo', 'seqhilo', 'identity' or 'sequence'. The Hibernate docs list the possible classes and their params. The next key is the word params and the value is another map. The keys for this map are name attributes of each of the param tags taken by this generator class. The values are the bodies of the param tags. In the case of the sequence generator we only have one param tag with a name attribute of sequence and the body would be the name of the sequence in the database, in our example 'ID_PUB_PK_SEQ' or 'ID_BK_PK_SEQ'.
One more note: We were able to talk our DBA into adding a number field called version to each of our legacy tables so we left versioning on. If you can not add a version field to your tables (and don't already have one) then you can turn off versioning by adding the line version false after the line where you declare your table. If you do this you will lose the optimistic concurrency that Grail / Hibernate give you and will have to provide some other method of handling concurrency.
There is a great deal more that you can do with the Grails ORM DSL, but I only wanted to discuss features that I've actually worked with. As I dig into this more I may add more details, but in the meantime you can read all about it in the Grails online docs.