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 configura- … tion language such as XML or annota- } tions, 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.

def networth = 0 accounts.each

{networth + it.balance} networth

}

class Customer { static transients = [“networth”]

 

static mapping = { id column: ‘customer _ id’ table ‘crc _ customer’

columns { name column: ‘customer _ name’

}

}

def getNetworth() {

In this example, the transients property, which is a list of property names, specifies that the networth property, which calculates the total balance of the customer’s accounts and is defined by the getNetworth() method, is not persistent. The mapping property maps the Customer class to the crc _ customer table; the id property to the customer _ id column; and the name property to the customer _ name property.

The value of the mapping property is a Groovy closure object, which is a kind of anonymous method. Although it might not be immediately apparent, the body of the mapping closure is a sequence of method calls. For example, "id column: 'customer _ id'" is a call to an id method with a map parameter containing a single entry that

has column: as the key and 'customer _ id' as the value.

The mapping closure is an example of a DSL (domain-specific language), 4 which is a mini-language for representing information about a domain. DSLs are used by Grails for a variety of configuration tasks. Groovy applications often define one or more DSLs as well. Several features of the Groovy language make it easy to write DSLs, including closures, literal lists and maps, and a flexible syntax that does not, for example, require parentheses around method arguments. They enable a developer to write highly readable and concise DSLs without having to go outside of the language and use mechanisms such as XML.

figure 4.

(a)

methclass

AccountDaoImpl .. { public List<Account> findByBalanceLessThan(double threshold) {

Session session = Session.currentSession();

Query query = session.createQuery(“from Account where balance < ?”) query.setParameter( 1, threshold); return (List<Account>) query.list();

}

(b)

class AccountDaoImpl .. { public List<Account> findByBalanceLessThan(double threshold) { Criteria c = session.createCriteria( Account.class) c.add( Restrictions.lt(“balance”, threshold)) return c.list();

}

figure 5.

(a)

def accounts = Account.findAllByBalanceLessThan(threshold)

(b)

List accounts = Account.findAll(“from Account where balance < ?”, [threshold])

(c)

def c = Account.createCriteria() def results = c.list {

lt(“balance”, threshold)

}

manipulating Persistent objects Applications must save, load, and delete persistent objects. A traditional ORM framework provides an API object that has methods for manipulating persistent data. GORM, however, takes a very different and simpler approach that leverages Groovy’s ability to define new methods at runtime.

When using a traditional ORM framework, the application manipulates persistent data by invoking methods on an API object. For example, a Hibernate application uses a Session object, which represents a connection to the database to save, load, and delete persistent objects. Note that usually an application needs only to save newly created objects. Most ORM frameworks, including Hibernate, track changes to persistent objects and automatically update the database.

Figure 3a shows a code snippet that illustrates how an application can load an account with the specified primary key. This code snippet obtains the current Session and calls get() to load the specified account.

An application’s business logic could use the Session directly. Doing so, however, would violate the Separation of Concerns principle. 3 The application code would be a mix of business logic and persistence logic, which makes it more complex and much more difficult to test. It also tightly couples the business logic to the ORM framework, which is undesirable given the furious rate at which Java EE frameworks evolve.

52 communicAtionS of the Acm | APriL 2009 | voL. 52 | no. 4

References:

Archives