Inside Gorm

27
Inside GORM Relational Data Mapping, Groovy-Style by Ken Rimple

description

A look at grails' ORM from back in 2009.

Transcript of Inside Gorm

Page 1: Inside Gorm

Inside GORM

Relational Data Mapping, Groovy-Style by Ken Rimple

Page 2: Inside Gorm

Goals

•  Learn GORM basics • Understand GORM within Grails •  Exploring GORM in a Spring MVC

Application

Page 3: Inside Gorm

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

Page 4: Inside Gorm

A Simple GORM Class

•  Lives in grails-app/domains •  Created with grails create-domain-class

class Person { String firstName String lastName }

Page 5: Inside Gorm

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)

Page 6: Inside Gorm

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

Page 7: Inside Gorm

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")

}

Page 8: Inside Gorm

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

Page 9: Inside Gorm

One To Many

•  Employee has Many Reviews: class Employee {

String empSSN …

static hasMany = [reviews:Review] }

class Review {

Date reviewDate String result Employee employee }

Page 10: Inside Gorm

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()

Page 11: Inside Gorm

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] }

Page 12: Inside Gorm

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()

Page 13: Inside Gorm

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

Page 14: Inside Gorm

Inheritance Hierarchies

•  Create one class, extend with another…

Page 15: Inside Gorm

Testing GORM

•  Interactive testing with the grails console • Within Grails, you can create integration

test cases

Page 16: Inside Gorm

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

Page 17: Inside Gorm

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>

Page 18: Inside Gorm

Necessary Pre-requisites

• Hibernate 3.x dependencies •  A mounted Data Source •  A ResourceBundleMessageSource – To store validation errors

Page 19: Inside Gorm

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??

Page 20: Inside Gorm

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") } }

Page 21: Inside Gorm

SimpleFormController Redux…

@Controller @RequestMapping(["/addEmployee.html"]) @SessionAttributes(types = [Employee.class]) class EditEmployeeForm {

@InitBinder void setAllowedFields(WebDataBinder dataBinder) { dataBinder.disallowedFields = [ 'id'] as String[] }

Page 22: Inside Gorm

SimpleFormController – Edit Form…

@RequestMapping(method = [RequestMethod.GET]) String setupForm(Model model) { Employee employee = new Employee() model.addAttribute(employee) return "employeeForm" }

Page 23: Inside Gorm

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 } }

}

Page 24: Inside Gorm

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>

Page 25: Inside Gorm

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

Page 26: Inside Gorm

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

Page 27: Inside Gorm

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