Advanced GORM - Beyond Relational

Post on 06-Jul-2015

681 views 0 download

description

In this talk, Grails project lead Graeme Rocher will demonstrate some less known, advanced features of GORM and explore the possibilities offered going beyond the relational database.

Transcript of Advanced GORM - Beyond Relational

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Advanced GORM - Beyond RelationalBy Graeme Rocher

Agenda

§ Understanding GORM Internals § GORM Standalone § Tips and Tricks § Jumping into MongoDB § Unit testing with GORM § Summary / Q & A

GORM

• Powerful multi-datastore query layer

• Dynamic finders, criteria, and persistence methods

• Integrated validation • Automatic mapping of entities

to underlying datastore • Easy access to native APIs

3

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Understanding what makes GORM tick

GORM Internals

Grails Data Mapping Project

• https://github.com/grails/grails-data-mapping

5

Built by Travis

• https://travis-ci.org/grails/grails-data-mapping

6

Developer Documentation

• http://grails.github.com/grails-data-mapping/

7

Important Subprojects• grails-datastore-core

– Core low level API

• grails-datastore-gorm– GORM API layer

• grails-datastore-gorm-tck– Test Suite

8

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Demo: Code Walkthrough

Contribute to GORM

• GORM is huge and sprawling • Covers loads of data stores • Great area to contribute to the

community. Some ideas: • Multi Tenancy • Elastic Search • Hadoop / HBase

10

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Use GORM outside of Grails

GORM Standalone

What is GORM Standalone?• Easy initialisation of GORM outside of Grails • And a set of Spring Boot plugins • Required modularisation of codebase • Reduction of external dependencies • Simplification of GORM setup

12

Standalone Entities• Annotated with grails.persistence.Entity

13

@Entity  class  Person  {          String  name          static  constraints  =  {                  name  blank:false          }  }

GORM for Hibernate Standalone• https://gist.github.com/graemerocher/c25ec929d9bcd1adcbea

14

@Grab("org.grails:grails-­‐datastore-­‐gorm-­‐hibernate4:3.1.2.RELEASE")  @Grab("com.h2database:h2:1.3.164")  

import  grails.orm.bootstrap.*  

init  =  new  HibernateDatastoreSpringInitializer(Person)  def  dataSource  =  new  DriverManagerDataSource(Driver.name,  "jdbc:h2:prodDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE",  'sa',  '')  init.configureForDataSource(dataSource)  

GORM for MongoDB Standalone• https://gist.github.com/graemerocher/9683650

15

@Grab("org.grails:grails-­‐datastore-­‐gorm-­‐mongodb:3.0.2.RELEASE")  

import  grails.mongodb.bootstrap.*  

init  =  new  MongoDbDataStoreSpringInitializer(Person)  init.configure()

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Demo: GORM Standalone

GORM for Hibernate in Spring Boot• Add gorm-hibernate4-spring-boot as a dependency

• Then add persistent entities that are annotated with grails.persistence.Entity

17

compile  "org.grails:gorm-­‐hibernate4-­‐spring-­‐boot:1.0.0.RELEASE"

GORM for MongoDB in Spring Boot• Add gorm-mongodb-spring-boot as a dependency

• Then add persistent entities that are annotated with grails.persistence.Entity

18

compile  "org.grails:gorm-­‐mongodb-­‐spring-­‐boot:1.1.0.RELEASE"

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Take GORM to the next level

Tips & Tricks

GORM Tips & Tricks• Understanding where queries • Working with DetachedCriteria • Using formula and column readers / writers • Going asynchronous

20

Where Queries• Type-safe, composable query API

21

DetachedCriteria<Person>  query  =                  Person.where  {                  lastName  ==  "Simpson"          }  

def  results  =  query.list()

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Demo: Where Queries

Hibernate Subqueries• Perform nested “in” or “notIn” sub queries that span domain

classes using where queries:

23

def  employees  =  Employee.where  {          region.continent  in  ['APAC',  "EMEA"]  }.id()  

def  results  =  Sale.where  {        employee  in  employees  &&  total  >  50000  }.employee.list()

Hibernate Correlated Subqueries• Declare aliases using “def” for cross query references:

24

def  query  =  Employee.where  {          def  em1  =  Employee          exists  Sale.where  {                  def  s1  =  Sale                  def  em2  =  employee                  return  em2.id  ==  em1.id          }.id()  }  def  results  =  query.list()

Hibernate Column Formula• A column can be a read-only formula

25

class  Product  {          Float  price          Float  taxRate          Float  tax          static  mapping  =  {                  tax  formula:  'PRICE  *  TAX_RATE'          }  }

Hibernate Column Readers/Writers• New in 2.4: Implement custom column readers and writers

to transform data when written or read from the database.

26

class  Name  {          String  title          static  mapping  =  {                  title  write:'UPPER(?)',                            read:'REPEAT(title,  2)'          }  }

Asynchronous GORM• Database operations are blocking • Can be helpful to isolate these blocking operations on a

separately managed thread • Work underway in some NoSQL datastore on fully

asynchronous drivers (MongoDB, CouchDB etc.) • No usable asynchronous SQL/JDBC drivers on the horizon

(to my knowledge)

27

Async Namespace• Any GORM method can become Async

28

import  static  grails.async.Promises.*  

def  p1  =  Person.async.get(1L)  def  p2  =  Person.async.get(2L)  def  p3  =  Person.async.get(3L)  def  results  =  waitAll(p1,  p2,  p3)

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Demo: Async GORM

Async Tasks• Individual async method calls often too fine grained, use

task method to implement Async GORM tasks

30

def  promise  =  Person.async.task  {          withTransaction  {                def  person  =  findByFirstName("Homer")                person.firstName  =  "Bart"                person.save(flush:true)                  }  }  Person  updatedPerson  =  promise.get()

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Go schemaless!

Jumping into MongoDB

GORM for MongoDB• Geospacial querying • GeoJSON models • Full text search • Schemaless domain models • Projections via MongoDB

aggregation • Stateless and Stateful modes • Custom user types

32

GORM for MongoDB Internals• MongoEntityPersister implements persistence • MongoQuery implements querying aggregation • MongoSession implements batch inserts, updates and

deletes • MongoGormStaticApi adds extra GORM methods • GeoJSONType and subclasses implement GeoJSON

custom types • https://github.com/grails/grails-data-mapping/tree/master/

grails-datastore-gorm-mongodb33

GORM, MongoDB & GeoJSON• Geo Data in MongoDB represented by GeoJSON types

– http://geojson.org • Package grails.mongodb.geo contains GeoJSON

types – Point, Polygon, LineString, MultiPoint, MultiLineString, MultiPolygon, GeometryCollection

34

Geospacial Querying

35

def  point  =  new  Point(2,  1)  def  p  =  new  Place(point:  point)  

def  poly1  =  Polygon        .valueOf([  [0.0,  0.0],  [3.0,  0.0],  [3.0,  3.0],  [0.0,  3.0],  [0.0,  0.0]  ])  

Place.findByPointGeoWithin(poly1)  

MongoDB Text Search• Create text indices and use methods

36

Product.search('"Coffee  Cake"')                                    .size()  ==  1  Product.searchTop("cake").size()  ==  4  Product.searchTop("cake",3).size()  ==  3  Product.countHits('coffee')  ==  5  

Schemaless Dynamic Properties• Add dynamic properties with the subscript operator

37

def  p  =  new  Plant(name:"Pineapple")  p.save()  p["color"]  =  "Yellow"  p["hasLeaves"]  =  true  

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Demo: GORM for MongoDB

Other Implementations• Neo4j

– http://grails.org/plugin/neo4j • Redis GORM

– http://grails.org/plugin/redis-gorm • GORM for REST

– http://grails.org/plugin/gorm-rest-client • Cassandra

– https://github.com/grails/grails-data-mapping/

39

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Spin up GORM inside a unit test

Unit Testing GORM

Hibernate in Unit Tests• Add a dependency on grails-datastore-test-support

• Provides HibernateTestMixin that will load Hibernate inside a unit test

41

test  "org.grails:grails-­‐datastore-­‐test-­‐support:1.0-­‐grails-­‐2.4"

Hibernate in Unit Tests

42

import  grails.test.mixin.TestMixin  import  grails.test.mixin.gorm.Domain  import  grails.test.mixin.hibernate.*  import  spock.lang.Specification  

@Domain(Person)  @TestMixin(HibernateTestMixin)  class  PersonSpec  extends  Specification  {        …  }

Summary• GORM provides a rich and diverse ecosystem • Goes far beyond relational databases • Can be used standalone or within Grails • Great area to contribute to!

43

Q & A

Stay Connected.

Web: grails.org StackOverflow: http://stackoverflow.com/tags/grails Twitter: http://twitter.com/grailsframework LinkedIn: http://linkedin.com/groups/Grails-User-Group-39757 Google+: https://plus.google.com/communities/109558563916416343008