Object-Relational
Mapping
ORM
in Dynamic
Languages
fields to store the primary key and a version number. The
primary-key field is usually required by Hibernate or by
a domain object’s clients. The version number is used for
optimistic locking. The trouble with these fields, however,
is that typically the application’s business logic does not
require them. They must be added to every domain class
solely to support persistence.
O/R MAPPING IN GORM
Grails relies heavily on Convention over Configuration
when defining ORM. It automatically treats classes in the
grails-app/domain directory as being persistent. GORM
automatically persists the properties of each class. It
defaults table and column names from the class and property names. GORM also adds primary-key and version-number properties to each class.
The following is an example domain class. The
Customer class has a field called name. Also, because this
field has default visibility, Groovy automatically defines
the name property by defining getName() and setName()
methods.
class Customer {
String name
}
GORM automatically maps the Customer class to the
customer table and maps the name property to the name
column. GORM adds an id property to the class and
maps it to a primary-key column called id. It also adds a
version property and maps it to a version column. Unlike
a traditional ORM framework, GORM requires very
little configuration, provided that the database schema
matches the defaults.
Another nice feature of GORM is that it will maintain
creation and last updated times for domain model classes.
You simply have to define lastUpdated and dateCreated
properties on your classes, and GORM will automatically
update them. In comparison, you must write code to do
this when using vanilla Hibernate.
GORM also makes it easy to map relationships by
using static properties to supply metadata in a similar
fashion to annotations in other languages. For example,
the static property hasMany defines the one-to-many
relationships for a domain class. The value of the hasMany
property is a map. Each map entry defines a one-to-many relationship: its key is the name of the property
that stores the collection, and its value is the class of the
collection elements. For each one-to-many relationship
GORM adds a property to store the collection of objects,
as well as methods for maintaining the relationship.
The following is an example of how to map a one-to-many relationship between the Customer class and the
Account class.
class Customer {
static hasMany = [accounts : Account]
}
class Account {
static belongs To = Customer
Customer customer
}
The collection of accounts is stored in a property
called accounts, which GORM adds to the Customer class
at runtime. The relationship is mapped using a foreign
key called customer_id in the account table. The belongs To
property specifies that a Customer owns the account and
it should be deleted if the customer is deleted.
GORM also dynamically defines a couple of methods
for managing this relationship. The add ToAccounts()
method adds an account to the collection, and the
removeFromAccounts() method removes an account.
These methods also maintain the inverse relationship
from Account to Customer. By automatically defining
these methods, which would otherwise have to be written by hand, GORM simplifies the code and makes it less
error prone.
CONFIGURING THE MAPPING
CoC reduces the amount of configuration that is required.
Sometimes, however, you need to specify some aspects
of the ORM. For example, table or column names might
not match the defaults, or perhaps a class has derived
properties that should not be persisted. To support these
requirements, GORM lets you specify various aspects of
the ORM. Rather than using a different configuration language such as XML or annotations, however, GORM uses
snippets of Groovy code in the domain classes.
Here is an example of how to override the default table
and column names and specify that a property should
not be persisted.