Inside Gorm
description
Transcript of Inside Gorm
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