Inside GORM
Relational Data Mapping, Groovy-Style
by Ken Rimple
Goals
•  Learn GORM basics
•  Understand GORM within Grails
•  Exploring GORM in a Spring MVC
Application
What is GORM?
•  Grails Object Relational Mapping
•  Wraps Hibernate 3.x using a Domain
Centered Architecture
•  GORM Objects written in Groovy
•  GORM Objects placed within convention-
based directory structure
•  GORM enables dynamic method calls to load
data
A Simple GORM Class
•  Lives in grails-app/domains
•  Created with grails create-domain-class
class Person {
String firstName
String lastName
}
Using the Class
•  Get all Person objects in the database:
def people = Person.findAll()
•  Get a Person Object by Last Name:
def smiths = Person.findByLastName("Smith")
•  Modify a Person
person.lastName = "Fred"
person.save()
•  Delete the person
Person.delete(person)
Benefits (so far)
•  You do not need a Repository/DAO
•  GORM Dynamic Syntax for Queries:
Person.findByLastNameLikeAndZipCode("R%", "19073")
•  But this could get complex.
•  Alternative… Using the GORM DSL
GORM Criteria Builder DSL
•  A Closure-based DSL for forming queries
•  More Query/SQL-like
•  Wraps the Hibernate Criteria API:
def c = Account.createCriteria()
def results = c {

like("holderFirstName", "Fred%")

and {

 
between("balance", 500, 1000)

 
eq("branch", "London")

}

maxResults(10)

order("holderLastName", "desc")
}
Relating Data Elements
•  GORM manages relationships
– One to Many
– Many to One
– Many to Many
– Inheritance Hierarchies
•  GORM uses attributes and directives in
closures to manage relationships
One To Many
•  Employee has Many Reviews:
class Employee {
String empSSN
…
static hasMany = [reviews:Review]
} 
class Review {
Date reviewDate
String result
Employee employee
}
Using the One To Many Relationship
•  Add a Review to the Employee:
def emp = new Employee(firstName:"Joe", lastName:"Smith").save()
emp.reviews = [new Review(employee:emp,comments:"Plays bad
piano",reviewDate: new Date("01/15/2001"))]
emp.save()
emp.reviews += new Review(employee:emp, comments:"Plays bad
piano", reviewDate: new Date("01/15/2001"))
emp.save()
Many to Many Relationships
•  Two hasMany mappings & one belongsTo
class Employee {
String firstName
String lastName
static hasMany = [reviews:Review, 
departmentAssignments:Department]
static belongsTo = Department
} 
class Department { 
String name
static hasMany = [employees:Employee]
}
Using the Many to Many Relationship
Department dSales = new Department(name:"Sales").save()
Department dConsulting = new Department(name:"Consulting").save()
Employee smith = new Employee(firstName:"Will", lastName:"Smith").save()
Employee jones = new Employee(firstName:"Joe", lastName:"Jones").save()
smith.departmentAssignments = [dSales, dConsulting]
jones.departmentAssignments = [dSales]
smith.save()
jones.save()
dSales.employees = [smith, jones]
dConsulting.employees = [smith]
dSales.save()
dConsulting.save()
One to One Relationship
•  Just use a reference to the other class
class SkillSet {
int research
int development
int qa
int projectmanagement
} 
class Employee {
String firstName
String lastName
SkillSet skillSet
…
}
def skillSet = new SkillSet(research:5, development:2, qa:0, 
projectmanagement:1).save()
def e = new Employee(firstName: "Smith", lastName: "Jones", 
skillSet: skillSet).save()
print e
Inheritance Hierarchies
•  Create one class, extend with another…
Testing GORM
•  Interactive testing with the grails console
•  Within Grails, you can create integration
test cases
GORM Outside of GRAILS
•  GORM can be executed in a Spring
application
– Add necessary JARs (maven repo, ivy)
– Mount a GORM factory in Spring
• Wire to datasource
• Define the package structure
• Annotate all Groovy Domain Objects with the
grails.persistence.Entity annotation
Setting up the Factory
<gorm:sessionFactory base-package="spring.kickstart.domain"
data-source-ref="dataSource"
message-source-ref="messageSource">
<property name="hibernateProperties">
<util:map>
<entry key="hibernate.hbm2ddl.auto" 
value="update"/>
</util:map>
</property>
</gorm:sessionFactory>
Necessary Pre-requisites
•  Hibernate 3.x dependencies
•  A mounted Data Source
•  A ResourceBundleMessageSource
– To store validation errors
Agile Web MVC – Groovy Controllers
•  Go all the way… Almost
•  Spring MVC is simplified in 2.x and 3
– Use annotations for controllers
– Follow conventions
– Write them in Groovy
– Create "open session in view"
•  Almost Grails – so why not use it??
A "Listing" Controller
@Controller
class MainController {
@RequestMapping(["/employees.html"])

public ModelMap employeesHandler() {

 
return new ModelMap(Employee.list())

}
@RequestMapping(["/index.html"])
public ModelAndView indexHander() {
return new ModelAndView("index")
}
}
SimpleFormController Redux…
@Controller
@RequestMapping(["/addEmployee.html"])
@SessionAttributes(types = [Employee.class])
class EditEmployeeForm {
@InitBinder
void setAllowedFields(WebDataBinder dataBinder) {
dataBinder.disallowedFields = [ 'id'] as String[]
}
…
SimpleFormController – Edit Form…

@RequestMapping(method = [RequestMethod.GET])

 
 
 
String setupForm(Model model) {

 
Employee employee = new Employee()

 
model.addAttribute(employee)

 
return "employeeForm"

}
SimpleFormController – Persist

@RequestMapping(method = [RequestMethod.POST])

String processSubmit(@ModelAttribute Employee employee,
BindingResult result, SessionStatus status) {

 if (!employee.validate()) {

 
 employee.errors.allErrors.each { result.addError it }

 
 return "employeeForm";

 } else {

 
 employee.save()

 
 status.setComplete();

 
 return "redirect:employees.html?employeeId=" +

 
 
 
 
employee.id

 
}

}
}
FORM JSP
<form:form modelAttribute="employee">
<table>
<tr>
<th>
First Name: <form:errors path="firstName" cssClass="errors"/>
<br/>
<form:input path="firstName" size="30" maxlength="30"/>
</th>
</tr>
…
<p class="submit"><input type="submit" value="Add Employee"/></p>
</form:form>
What do you get?
•  Hibernate mappings via closures and
references
•  Reduce complexity of searching/
persisting
•  Form validation via GORM constraints
•  Access to hibernate mapping settings
What don't you get?
•  GRAILS
– Dynamic, automatic scaffolding
– An integrated test environment
– A Groovy console that can test your domains
– Plugins for just about anything
– Decent tooling support
– You manage your own build process
Summary
•  Grails is powerful, due to Groovy and
GORM (and other things)
•  If you want the flexibility of Spring
MVC/WebFlow but need agility of
GORM, you now have options
•  I still suggest weighing using GORM –vs-
all-in Grails carefully

Inside Gorm

  • 1.
    Inside GORM Relational DataMapping, Groovy-Style by Ken Rimple
  • 2.
    Goals •  Learn GORMbasics •  Understand GORM within Grails •  Exploring GORM in a Spring MVC Application
  • 3.
    What is GORM? • Grails Object Relational Mapping •  Wraps Hibernate 3.x using a Domain Centered Architecture •  GORM Objects written in Groovy •  GORM Objects placed within convention- based directory structure •  GORM enables dynamic method calls to load data
  • 4.
    A Simple GORMClass •  Lives in grails-app/domains •  Created with grails create-domain-class class Person { String firstName String lastName }
  • 5.
    Using the Class • Get all Person objects in the database: def people = Person.findAll() •  Get a Person Object by Last Name: def smiths = Person.findByLastName("Smith") •  Modify a Person person.lastName = "Fred" person.save() •  Delete the person Person.delete(person)
  • 6.
    Benefits (so far) • You do not need a Repository/DAO •  GORM Dynamic Syntax for Queries: Person.findByLastNameLikeAndZipCode("R%", "19073") •  But this could get complex. •  Alternative… Using the GORM DSL
  • 7.
    GORM Criteria BuilderDSL •  A Closure-based DSL for forming queries •  More Query/SQL-like •  Wraps the Hibernate Criteria API: def c = Account.createCriteria() def results = c { like("holderFirstName", "Fred%") and { between("balance", 500, 1000) eq("branch", "London") } maxResults(10) order("holderLastName", "desc") }
  • 8.
    Relating Data Elements • GORM manages relationships – One to Many – Many to One – Many to Many – Inheritance Hierarchies •  GORM uses attributes and directives in closures to manage relationships
  • 9.
    One To Many • Employee has Many Reviews: class Employee { String empSSN … static hasMany = [reviews:Review] } class Review { Date reviewDate String result Employee employee }
  • 10.
    Using the OneTo Many Relationship •  Add a Review to the Employee: def emp = new Employee(firstName:"Joe", lastName:"Smith").save() emp.reviews = [new Review(employee:emp,comments:"Plays bad piano",reviewDate: new Date("01/15/2001"))] emp.save() emp.reviews += new Review(employee:emp, comments:"Plays bad piano", reviewDate: new Date("01/15/2001")) emp.save()
  • 11.
    Many to ManyRelationships •  Two hasMany mappings & one belongsTo class Employee { String firstName String lastName static hasMany = [reviews:Review, departmentAssignments:Department] static belongsTo = Department } class Department { String name static hasMany = [employees:Employee] }
  • 12.
    Using the Manyto Many Relationship Department dSales = new Department(name:"Sales").save() Department dConsulting = new Department(name:"Consulting").save() Employee smith = new Employee(firstName:"Will", lastName:"Smith").save() Employee jones = new Employee(firstName:"Joe", lastName:"Jones").save() smith.departmentAssignments = [dSales, dConsulting] jones.departmentAssignments = [dSales] smith.save() jones.save() dSales.employees = [smith, jones] dConsulting.employees = [smith] dSales.save() dConsulting.save()
  • 13.
    One to OneRelationship •  Just use a reference to the other class class SkillSet { int research int development int qa int projectmanagement } class Employee { String firstName String lastName SkillSet skillSet … } def skillSet = new SkillSet(research:5, development:2, qa:0, projectmanagement:1).save() def e = new Employee(firstName: "Smith", lastName: "Jones", skillSet: skillSet).save() print e
  • 14.
    Inheritance Hierarchies •  Createone class, extend with another…
  • 15.
    Testing GORM •  Interactivetesting with the grails console •  Within Grails, you can create integration test cases
  • 16.
    GORM Outside ofGRAILS •  GORM can be executed in a Spring application – Add necessary JARs (maven repo, ivy) – Mount a GORM factory in Spring • Wire to datasource • Define the package structure • Annotate all Groovy Domain Objects with the grails.persistence.Entity annotation
  • 17.
    Setting up theFactory <gorm:sessionFactory base-package="spring.kickstart.domain" data-source-ref="dataSource" message-source-ref="messageSource"> <property name="hibernateProperties"> <util:map> <entry key="hibernate.hbm2ddl.auto" value="update"/> </util:map> </property> </gorm:sessionFactory>
  • 18.
    Necessary Pre-requisites •  Hibernate3.x dependencies •  A mounted Data Source •  A ResourceBundleMessageSource – To store validation errors
  • 19.
    Agile Web MVC– Groovy Controllers •  Go all the way… Almost •  Spring MVC is simplified in 2.x and 3 – Use annotations for controllers – Follow conventions – Write them in Groovy – Create "open session in view" •  Almost Grails – so why not use it??
  • 20.
    A "Listing" Controller @Controller classMainController { @RequestMapping(["/employees.html"]) public ModelMap employeesHandler() { return new ModelMap(Employee.list()) } @RequestMapping(["/index.html"]) public ModelAndView indexHander() { return new ModelAndView("index") } }
  • 21.
    SimpleFormController Redux… @Controller @RequestMapping(["/addEmployee.html"]) @SessionAttributes(types =[Employee.class]) class EditEmployeeForm { @InitBinder void setAllowedFields(WebDataBinder dataBinder) { dataBinder.disallowedFields = [ 'id'] as String[] } …
  • 22.
    SimpleFormController – EditForm… @RequestMapping(method = [RequestMethod.GET]) String setupForm(Model model) { Employee employee = new Employee() model.addAttribute(employee) return "employeeForm" }
  • 23.
    SimpleFormController – Persist @RequestMapping(method= [RequestMethod.POST]) String processSubmit(@ModelAttribute Employee employee, BindingResult result, SessionStatus status) { if (!employee.validate()) { employee.errors.allErrors.each { result.addError it } return "employeeForm"; } else { employee.save() status.setComplete(); return "redirect:employees.html?employeeId=" + employee.id } } }
  • 24.
    FORM JSP <form:form modelAttribute="employee"> <table> <tr> <th> FirstName: <form:errors path="firstName" cssClass="errors"/> <br/> <form:input path="firstName" size="30" maxlength="30"/> </th> </tr> … <p class="submit"><input type="submit" value="Add Employee"/></p> </form:form>
  • 25.
    What do youget? •  Hibernate mappings via closures and references •  Reduce complexity of searching/ persisting •  Form validation via GORM constraints •  Access to hibernate mapping settings
  • 26.
    What don't youget? •  GRAILS – Dynamic, automatic scaffolding – An integrated test environment – A Groovy console that can test your domains – Plugins for just about anything – Decent tooling support – You manage your own build process
  • 27.
    Summary •  Grails ispowerful, due to Groovy and GORM (and other things) •  If you want the flexibility of Spring MVC/WebFlow but need agility of GORM, you now have options •  I still suggest weighing using GORM –vs- all-in Grails carefully