Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Advanced GORM - Beyond Relational

graemerocher
September 10, 2014

Advanced GORM - Beyond Relational

Talk by Graeme Rocher at SpringOne2GX 2014 on Advanced GORM

graemerocher

September 10, 2014
Tweet

More Decks by graemerocher

Other Decks in Programming

Transcript

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

    without permission. Advanced GORM - Beyond Relational By Graeme Rocher
  2. Agenda § Understanding GORM Internals § GORM Standalone § Tips

    and Tricks § Jumping into MongoDB § Unit testing with GORM § Summary / Q & A
  3. 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
  4. © 2014 SpringOne 2GX. All rights reserved. Do not distribute

    without permission. Understanding what makes GORM tick GORM Internals
  5. Important Subprojects • grails-datastore-core! – Core low level API •

    grails-datastore-gorm! – GORM API layer • grails-datastore-gorm-tck! – Test Suite 8
  6. © 2014 SpringOne 2GX. All rights reserved. Do not distribute

    without permission. Demo: Code Walkthrough
  7. 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
  8. © 2014 SpringOne 2GX. All rights reserved. Do not distribute

    without permission. Use GORM outside of Grails GORM Standalone
  9. 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
  10. Standalone Entities • Annotated with grails.persistence.Entity 13 @Entity   class

     Person  {          String  name          static  constraints  =  {                  name  blank:false          }   }
  11. 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=FALS E",  'sa',  '')   init.configureForDataSource(dataSource)  
  12. 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()
  13. © 2014 SpringOne 2GX. All rights reserved. Do not distribute

    without permission. Demo: GORM Standalone
  14. 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"
  15. 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"
  16. © 2014 SpringOne 2GX. All rights reserved. Do not distribute

    without permission. Take GORM to the next level Tips & Tricks
  17. GORM Tips & Tricks • Understanding where queries • Working

    with DetachedCriteria • Using formula and column readers / writers • Going asynchronous 20
  18. Where Queries • Type-safe, composable query API 21 ! DetachedCriteria<Person>

     query  =                  Person.where  {                  lastName  ==  "Simpson"          }   ! def  results  =  query.list()
  19. © 2014 SpringOne 2GX. All rights reserved. Do not distribute

    without permission. Demo: Where Queries
  20. 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()
  21. 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()
  22. 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'          }   }
  23. 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)'          }   }
  24. 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
  25. 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)
  26. 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()
  27. © 2014 SpringOne 2GX. All rights reserved. Do not distribute

    without permission. Go schemaless! Jumping into MongoDB
  28. 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
  29. 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-mongodb 33
  30. 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
  31. 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)  
  32. 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  
  33. 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  
  34. © 2014 SpringOne 2GX. All rights reserved. Do not distribute

    without permission. Demo: GORM for MongoDB
  35. 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
  36. © 2014 SpringOne 2GX. All rights reserved. Do not distribute

    without permission. Spin up GORM inside a unit test Unit Testing GORM
  37. 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"
  38. 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  {        …   }
  39. 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
  40. 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