Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

6 things you need to know about GORM 6

514 views

Published on

GORM is the data access technology offered by Grails, and one of its spin-offs. This talk covers the 6 most important new features of GORM 6:

GORM without Grails and without Spring.
Multi-tenancy.
RxGORM.
Multiple datasource support.
Unit testing.
Data Services.

Published in: Software
  • Be the first to comment

6 things you need to know about GORM 6

  1. 1. 6 things you need to know about GORM 6 Álvaro Sánchez-Mariscal @alvaro_sanchez
  2. 2. About me — Coming from Madrid ! — Developer since 2001 (Java / Spring stack). — Grails fanboy since v0.4. — Working @ OCI since 2015: Groovy, Grails & Micronaut! — Father since 2017! " @alvaro_sanchez
  3. 3. 1. GORM without Grails / Spring Boot / Micronaut @alvaro_sanchez
  4. 4. build.gradle dependencies { compile 'org.codehaus.groovy:groovy:2.5.0' compile "org.grails:grails-datastore-gorm-hibernate5:6.1.9.RELEASE" compile 'org.hibernate:hibernate-validator:6.0.2.Final' compileOnly 'org.glassfish.web:el-impl:2.2.1-b05' runtime 'org.glassfish:javax.el:3.0.1-b08' runtime "com.h2database:h2:1.4.192" runtime "org.apache.tomcat:tomcat-jdbc:8.5.0" runtime "org.apache.tomcat.embed:tomcat-embed-logging-log4j:8.5.0" runtime "org.slf4j:slf4j-api:1.7.10" runtime "ch.qos.logback:logback-classic:1.2.3" testCompile "org.spockframework:spock-core:1.1-groovy-2.4" } @alvaro_sanchez
  5. 5. 2. Data Services @alvaro_sanchez
  6. 6. Data Services Auto-generated persistence logic from interfaces and abstract classes @Service(Book) interface BookService { Book getBook(Serializable id) } @alvaro_sanchez
  7. 7. Advantages — Type safety. — Signatures statically compiled. — Testing — Since they are interfaces, can be easily tested with Spock mocks. @alvaro_sanchez
  8. 8. Advantages — Performance. — No runtime proxies, eveything is compile-time. — Transaction management. — Methods are wrapped in a transaction (read-only for read operations). @alvaro_sanchez
  9. 9. Abstract classes support @Service(Book) abstract class BookService { abstract Book getBook(Serializable id) abstract Author getAuthor(Serializable id) Book updateBook(Serializable id, Serializable authorId) { Book book = getBook(id) if(book != null) { Author author = getAuthor(authorId) if(author == null) throw new IllegalArgumentException("Author does not exist") book.author = author book.save() } return book } } @alvaro_sanchez
  10. 10. Pagination support Data service: @Service(Book) interface BookService { List<Book> findBooks(String title, Map args) } Usage: List<Book> books = bookService.findBooks( "The Stand", [offset:10, max:10, sort:'title', order:'desc'] ) @alvaro_sanchez
  11. 11. "Dynamic finder"-like queries Just that they are statically compiled! @Service(Book) interface BookService { List<Book> findByTitleAndPublishDateGreaterThan(String title, Date publishDate) } @alvaro_sanchez
  12. 12. Where queries @Service(Book) interface BookService { @Where({ title ==~ pattern && releaseDate > fromDate }) Book searchBooks(String pattern, Date fromDate) } @alvaro_sanchez
  13. 13. Query joins @Service(Book) interface BookService { @Join('author') Book find(String title) @Join(value='author', type=LEFT) Book findAnother(String title) } @alvaro_sanchez
  14. 14. HQL queries @Service(Book) interface BookService { @Query("from ${Book book} where ${book.title} like $pattern") Book searchByTitle(String pattern) } @alvaro_sanchez
  15. 15. Projections @Service(Book) interface BookService { Date findBookReleaseDate(String title) List<Date> findBookReleaseDate(String publisher) @Query("select $b.releaseDate from ${Book b} where $b.publisher = $publisher order by $b.releaseDate") List<Date> findBookReleaseDatesHql(String publisher) } @alvaro_sanchez
  16. 16. 3. Unit testing @alvaro_sanchez
  17. 17. Unit testing class ClubSpec extends Specification { @Shared @AutoCleanup HibernateDatastore hibernateDatastore void setupSpec() { hibernateDatastore = new HibernateDatastore(Club) } @Rollback void "it can persist clubs"() { when: new Club(name: "Real Madrid").save(flush: true) then: Club.count() == old(Club.count()) + 1 } } @alvaro_sanchez
  18. 18. 4. Multiple datasources @alvaro_sanchez
  19. 19. application.yml dataSource: dbCreate: create-drop url: "jdbc:h2:mem:laliga" dataSources: premier: dbCreate: create-drop url: "jdbc:h2:mem:premier" @alvaro_sanchez
  20. 20. Domain class class Club { static mapping = { datasource ConnectionSource.ALL } String name String stadium } @alvaro_sanchez
  21. 21. Data source namespace Club.premier.findByName("Liverpool") //... Club rma = new Club(name: "Real Madrid") club.save() // Default data source @alvaro_sanchez
  22. 22. 5. Multi-Tenancy @alvaro_sanchez
  23. 23. Modes — DATABASE: a separate database with a separate connection pool is used to store each tenants data. — SCHEMA: the same database, but different schemas are used to store each tenants data. — DISCRIMINATOR - The same database is used with a discriminator used to partition and isolate data. @alvaro_sanchez
  24. 24. AST Transformations — @CurrentTenant: resolve the current tenant for the context of a class or method. — @Tenant: use a specific tenant for the context of a class or method — @WithoutTenant: execute logic without a specific tenant (using the default connection) @alvaro_sanchez
  25. 25. AST Transformations @CurrentTenant // resolve the current tenant for every method class TeamService { @WithoutTenant // execute the countPlayers method without a tenant id int countPlayers() { Player.count() } @Tenant({"another"}) // use the tenant id "another" for all GORM logic within the method List<Team> allTwoTeams() { Team.list() } List<Team> listTeams() { Team.list(max:10) } @Transactional void addTeam(String name) { new Team(name:name).save(flush:true) } } @alvaro_sanchez
  26. 26. Configuration grails: gorm: multiTenancy: mode: DATABASE tenantResolverClass: org.grails.datastore.mapping.multitenancy.web.SubDomainTenantResolver @alvaro_sanchez
  27. 27. Domain classes class Book implements MultiTenant<Book> { String title } @alvaro_sanchez
  28. 28.  Querying List<Book> books = withCurrent { Book.list() } //... List<Book> books = withId("otherTenant") { Book.list() } @alvaro_sanchez
  29. 29. 6. RxGORM @alvaro_sanchez
  30. 30. Domain class class Club implements RxMongoEntity<Club> { ObjectId id String name String stadium } @alvaro_sanchez
  31. 31.  GORM operations new Book(title:"The Stand") .save() // Returns an rx.Observable<Book> .subscribe { Book it -> // If you don't subscribe, it won't be executed println "ID = ${book.id}" } @alvaro_sanchez
  32. 32. Q & A Álvaro Sánchez-Mariscal @alvaro_sanchez

×