SlideShare a Scribd company logo
Groovy: Efficiency Oriented Programming
Lecture 11
Master Proteomics & Bioinformatics - University of Geneva
Alexandre Masselot - summer 2011
Agenda

‣ CRUD
‣ Integration tests
‣ Domain relationships
‣ Application configuration
groovy & grails - lecture 11
One domain based app ↔ one database
One domain class ↔ one table
One domain bean ↔ one table entry
One bean operations: CRUD
One bean operations: CRUD


         Action

        Create

         Read

        Update

         Delete
One bean operations: CRUD


         Action

        Create

         Read

        Update

         Delete
One bean operations: CRUD


         Action

        Create

         Read

        Update

         Delete
One bean operations: CRUD


         Action

        Create

         Read

        Update

         Delete
One bean operations: CRUD


         Action       SQL    Grails url

        Create      INSERT   create

         Read       SELECT    show

        Update      UPDATE   update

         Delete     DELETE   delete
One bean operations: CRUD


         Action       SQL    Grails url

        Create      INSERT   create

         Read       SELECT    show

        Update      UPDATE   update

         Delete     DELETE   delete
One bean operations: CRUD


         Action       SQL    Grails url

        Create      INSERT   create

         Read       SELECT    show

        Update      UPDATE   update

         Delete     DELETE   delete
Person joe = new Person(params)
   ➙ bean but no database entry creation
joe.save()
     ➙ insertion into table
(only if valid bean - constraints)
Validation

‣ Create only a valid bean
‣ 3 validation ways
Validation

‣ Create only a valid bean
‣ 3 validation ways
‣ Check explicitly for validation
 joe.validate()
Validation

‣ Create only a valid bean
‣ 3 validation ways
‣ Check explicitly for validation
 joe.validate()

‣ Save a catch exception
 joe.save(failOnError:true)
Validation

‣ Create only a valid bean
‣ 3 validation ways
‣ Check explicitly for validation
 joe.validate()

‣ Save a catch exception
 joe.save(failOnError:true)

‣ Save a check for non-null return
 assert joe.save()
Registered bean ⇔ joe.id != null
Reading a bean from the database
joe = Person.get(beanId)
Dynamic finders: retrieve from constraints
Dynamic finders (for single return)

‣ Domain class definition generate static methods
 def p = Person.findByUsername(‘lucky_luke’)
 def p = Person.findByFirstName(‘Lucky’)
 def p = Person.findByFirstNameAndLastName(‘Joe’, ‘Dalton’)
Dynamic finders (for single return)

‣ Domain class definition generate static methods
 def p = Person.findByUsername(‘lucky_luke’)
 def p = Person.findByFirstName(‘Lucky’)
 def p = Person.findByFirstNameAndLastName(‘Joe’, ‘Dalton’)

‣ Multiple results => returns first (sorted on id)
 def p = Person.findByLastName(‘Dalton’)
Dynamic finders (for single return)

‣ Domain class definition generate static methods
 def p = Person.findByUsername(‘lucky_luke’)
 def p = Person.findByFirstName(‘Lucky’)
 def p = Person.findByFirstNameAndLastName(‘Joe’, ‘Dalton’)

‣ Multiple results => returns first (sorted on id)
 def p = Person.findByLastName(‘Dalton’)

‣ findByXxxx efficient with unique:true fields
Update



  ‣ Update: change fields values and save into database
Update



  ‣ Update: change fields values and save into database
  1. modify bean as usual
Update



  ‣ Update: change fields values and save into database
  1. modify bean as usual
  2. validate/save as for creation
joe.delete() removes entry from table
Scaffolded controller hides CRUD operations
Explicit controller

‣ It is possible to generate scaffold controller code
 generate-controller eop.lec11.twitter.Person
Explicit controller

‣ It is possible to generate scaffold controller code
 generate-controller eop.lec11.twitter.Person

‣ PersonController.groovy write operation & test
Explicit controller

‣ It is possible to generate scaffold controller code
 generate-controller eop.lec11.twitter.Person

‣ PersonController.groovy write operation & test
‣ For example, read:
     def show = {
         def personInstance = Person.get(params.id)
         if (!personInstance) {
             flash.message = "${message(code:
 'default.not.found.message', .....)}"
             redirect(action: "list")
         }
         else {
             [personInstance: personInstance]
         }
     }
Time to go back to test!
Unit testing ↔ no dependency
Integration testing ↔ more complex biotope
Integration tests

‣ Resides under test/integration/
PersonIntegrationTests.groovy
Integration tests

‣ Resides under test/integration/
PersonIntegrationTests.groovy

‣ Launched with
test-app -integration
Integration tests

‣ Resides under test/integration/
 PersonIntegrationTests.groovy

‣ Launched with
 test-app -integration

‣ Results:
  - summary on the console output (count success/failures)
  - html files under target/tests-reports/html

  - plain text files under target/tests-reports/html
  - failure summary available
  - stdout/stderr accessible for each test case
Faster grails command

‣ Launch command (<alt><ctrl>G) interactive
Faster grails command

‣ Launch command (<alt><ctrl>G) interactive
‣ On the console, enter command
test-app -integration
Faster grails command

‣ Launch command (<alt><ctrl>G) interactive
‣ On the console, enter command
 test-app -integration

‣ Hit enter to relaunch last command
Faster grails command

‣ Launch command (<alt><ctrl>G) interactive
‣ On the console, enter command
 test-app -integration

‣ Hit enter to relaunch last command
‣ After several commands, PermGenException can occur
  - terminate
  - relaunch interactive
Grails integration testing cons




         ‣ Slower to execute than unit
Grails integration testing cons




         ‣ Slower to execute than unit
         ‣ Test report is not integrated into eclipse
Grails integration testing cons




         ‣ Slower to execute than unit
         ‣ Test report is not integrated into eclipse
         ‣ Use only when unit test not possible
mockDomain: unit testing with domain class
mockDomain

‣ It is possible to make some unit testing with domain
mockDomain

‣ It is possible to make some unit testing with domain
‣ No real database is connected, but a fake layer
mockDomain

‣ It is possible to make some unit testing with domain
‣ No real database is connected, but a fake layer
‣ In each method (not setup())
 mockDomain(Person)
 mockDomain(Person, initialBeanList)
mockDomain

‣ It is possible to make some unit testing with domain
‣ No real database is connected, but a fake layer
‣ In each method (not setup())
 mockDomain(Person)
 mockDomain(Person, initialBeanList)

‣ All single domain CRUD (and more) operations possible
mockDomain example


 void testDelete(){
     //buildDaltonFamily() return a list of 4 Person

 
 mockDomain(Person, buildDaltonFamily())


 
     assert Person.count() == 4

 
     Person p=Person.findByUsername('joe_dalton')

 
     assertNotNull p


 
     p.delete()


   
   // we should only have 3 members left

   
   assert Person.count() == 3

   
   p=Person.findByUsername('joe_dalton')

   
   assertNull p

   }
mockDomain limits



‣ No explicit database operation (hibernate criteria, HQL) are
  possible
mockDomain limits



‣ No explicit database operation (hibernate criteria, HQL) are
  possible
‣ Multiple domain class interaction are fully possible (cf.
  relationships)
mockDomain limits



‣ No explicit database operation (hibernate criteria, HQL) are
  possible
‣ Multiple domain class interaction are fully possible (cf.
  relationships)
‣ Connection with data already entered in a database
Hermit domain not very useful
Need for relationships
Twitter: Person ↔ Message
Message domain

create-domain-class Domain
Message domain

create-domain-class Domain

‣ Just a text (String) and a commiter (Person)
class Message {
    String text
    Person commiter

    static constraints = {
        text(size:1..140, blank:false)
        commiter(nullable:false)
    }
}
Message + Person

‣ Attach two messages to a user
 Person joe=Person.findByUsername('joe_dalton')
 new Message(text:'hello', commiter:joe).save()
 new Message(text:'world', commiter:joe).save()
Message + Person

‣ Attach two messages to a user
 Person joe=Person.findByUsername('joe_dalton')
 new Message(text:'hello', commiter:joe).save()
 new Message(text:'world', commiter:joe).save()

‣ Look for message from joe
 Message.findAllByCommiter(joe)
Message + Person

‣ Attach two messages to a user
 Person joe=Person.findByUsername('joe_dalton')
 new Message(text:'hello', commiter:joe).save()
 new Message(text:'world', commiter:joe).save()

‣ Look for message from joe
 Message.findAllByCommiter(joe)

‣ Not possible to access to message directly from joe bean
  - one solution: explicitly declare setCommiter(Person p) in
    Message.groovy that would add the message to a list in joe;
  - problem for deletion, save inconsistency...
Define a one-to-many relationship
One-to-many relationship



‣Message.groovy
//Person commiter
static belongsTo = [commiter:Person]
One-to-many relationship



‣Message.groovy
//Person commiter
static belongsTo = [commiter:Person]




‣Person.groovy
static hasMany = [messages: Message]
One-to-many relationship                        (cont’d)



‣ Add a message:
joe.addToMessages(new Message(text:‘hello world’)).save()
One-to-many relationship                         (cont’d)



‣ Add a message:
 joe.addToMessages(new Message(text:‘hello world’)).save()

‣ Will execute the following actions
  - create a message with joe as commiter
  - save the message
  - add the message to joe’s list
One-to-many relationship   (cont’d)

‣ Access to the list
 joe.messages
One-to-many relationship                                     (cont’d)

‣ Access to the list
 joe.messages

‣ Deleting will cascade
 joe.delete()
  - all messages with joe as commiter will also be deleted
Testing

‣ Test database consistency with two domain: integration testing
     // taken from MessageIntegrationTests.groovy
     // 4 Person are added in the setup() method
 
   public void testListMessagesUserDeletion(){
 
   
 Person joe=Person.findByUsername('joe_dalton')
 
   
 Person averell=Person.findByUsername('averell_dalton')
 
   
 
   
 joe.addToMessages(new Message(text:'hello world')).save()
 
   
 joe.addToMessages(new Message(text:'i'm running')).save()
 
   
 averell.addToMessages(new Message(text:'i'm eating')).save()
 
   
 
   
 assert Message.count() == 3
 
   
 assert Person.count() == 4
 
   
 
   
 joe.delete()
 
   
 assert Person.count() == 3

 
 
    //having deleted joe should delete all message related to joe
 
 
    assert Message.count() == 1
 
 }
Back to the web: 2 scaffolded controllers
groovy & grails - lecture 11
groovy & grails - lecture 11
groovy & grails - lecture 11

More Related Content

KEY
groovy & grails - lecture 12
KEY
groovy & grails - lecture 13
KEY
groovy & grails - lecture 2
KEY
groovy & grails - lecture 4
KEY
groovy & grails - lecture 5
ZIP
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume Laforge
PDF
Custom deployments with sbt-native-packager
PDF
Testing Web Applications with GEB
groovy & grails - lecture 12
groovy & grails - lecture 13
groovy & grails - lecture 2
groovy & grails - lecture 4
groovy & grails - lecture 5
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume Laforge
Custom deployments with sbt-native-packager
Testing Web Applications with GEB

What's hot (20)

PDF
Short Introduction To "perl -d"
PDF
Stubる - Mockingjayを使ったHTTPクライアントのテスト -
PDF
Apache Groovy: the language and the ecosystem
PDF
Smoking docker
PDF
Object Trampoline: Why having not the object you want is what you need.
PDF
The $path to knowledge: What little it take to unit-test Perl.
PDF
GoCracow #5 Bartlomiej klimczak - GoBDD
ODP
Practical git for developers
PDF
Keeping objects healthy with Object::Exercise.
PDF
Get your teeth into Plack
PDF
10 Cool Facts about Gradle
PDF
Challenges of container configuration
PDF
BASH Variables Part 1: Basic Interpolation
PDF
Pragmatic Browser Automation with Geb - GIDS 2015
PDF
Hypers and Gathers and Takes! Oh my!
PDF
Memory Manglement in Raku
PDF
Lean React - Patterns for High Performance [ploneconf2017]
PDF
The Groovy Way of Testing with Spock
PDF
Apache CouchDB talk at Ontario GNU Linux Fest
PDF
Testing Backbone applications with Jasmine
Short Introduction To "perl -d"
Stubる - Mockingjayを使ったHTTPクライアントのテスト -
Apache Groovy: the language and the ecosystem
Smoking docker
Object Trampoline: Why having not the object you want is what you need.
The $path to knowledge: What little it take to unit-test Perl.
GoCracow #5 Bartlomiej klimczak - GoBDD
Practical git for developers
Keeping objects healthy with Object::Exercise.
Get your teeth into Plack
10 Cool Facts about Gradle
Challenges of container configuration
BASH Variables Part 1: Basic Interpolation
Pragmatic Browser Automation with Geb - GIDS 2015
Hypers and Gathers and Takes! Oh my!
Memory Manglement in Raku
Lean React - Patterns for High Performance [ploneconf2017]
The Groovy Way of Testing with Spock
Apache CouchDB talk at Ontario GNU Linux Fest
Testing Backbone applications with Jasmine
Ad

Similar to groovy & grails - lecture 11 (20)

PDF
GR8Conf 2011: GORM Optimization
PDF
Singletons in PHP - Why they are bad and how you can eliminate them from your...
ODP
Spring 4 final xtr_presentation
PPT
Groovy Basics
PPT
Zend framework 03 - singleton factory data mapper caching logging
PDF
Writing JavaScript that doesn't suck
PPTX
Orchestration? You Don't Need Orchestration. What You Want is Choreography.
KEY
Sprout core and performance
PDF
Overview of Grails Object Relational Mapping (GORM)
PPT
What's New in Groovy 1.6?
PDF
Griffon @ Svwjug
PPTX
Adding a modern twist to legacy web applications
KEY
Test First Refresh Second: Test-Driven Development in Grails
KEY
Test First, Refresh Second: Web App TDD in Grails
PPTX
KEY
Javascript unit testing, yes we can e big
PDF
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
PDF
Building Testable PHP Applications
KEY
Writing your Third Plugin
GR8Conf 2011: GORM Optimization
Singletons in PHP - Why they are bad and how you can eliminate them from your...
Spring 4 final xtr_presentation
Groovy Basics
Zend framework 03 - singleton factory data mapper caching logging
Writing JavaScript that doesn't suck
Orchestration? You Don't Need Orchestration. What You Want is Choreography.
Sprout core and performance
Overview of Grails Object Relational Mapping (GORM)
What's New in Groovy 1.6?
Griffon @ Svwjug
Adding a modern twist to legacy web applications
Test First Refresh Second: Test-Driven Development in Grails
Test First, Refresh Second: Web App TDD in Grails
Javascript unit testing, yes we can e big
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Building Testable PHP Applications
Writing your Third Plugin
Ad

More from Alexandre Masselot (10)

PDF
Offshoring software development in Switzerland: You can do it
PDF
Dev Wednesday - Swiss Transport in Real Time: Tribulations in the Big Data Stack
PDF
Swiss Transport in Real Time: Tribulations in the Big Data Stack
KEY
groovy & grails - lecture 8
KEY
groovy & grails - lecture 10
KEY
groovy & grails - lecture 1
KEY
groovy & grails - lecture 9
KEY
groovy & grails - lecture 7
KEY
groovy & grails - lecture 6
KEY
groovy & grails - lecture 3
Offshoring software development in Switzerland: You can do it
Dev Wednesday - Swiss Transport in Real Time: Tribulations in the Big Data Stack
Swiss Transport in Real Time: Tribulations in the Big Data Stack
groovy & grails - lecture 8
groovy & grails - lecture 10
groovy & grails - lecture 1
groovy & grails - lecture 9
groovy & grails - lecture 7
groovy & grails - lecture 6
groovy & grails - lecture 3

Recently uploaded (20)

PPTX
Big Data Technologies - Introduction.pptx
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PDF
Electronic commerce courselecture one. Pdf
PDF
Unlocking AI with Model Context Protocol (MCP)
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
cuic standard and advanced reporting.pdf
PDF
NewMind AI Weekly Chronicles - August'25-Week II
PDF
Machine learning based COVID-19 study performance prediction
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
PPTX
Machine Learning_overview_presentation.pptx
PDF
Encapsulation theory and applications.pdf
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PDF
Empathic Computing: Creating Shared Understanding
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PDF
Encapsulation_ Review paper, used for researhc scholars
PDF
Getting Started with Data Integration: FME Form 101
PDF
Assigned Numbers - 2025 - Bluetooth® Document
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
Big Data Technologies - Introduction.pptx
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Electronic commerce courselecture one. Pdf
Unlocking AI with Model Context Protocol (MCP)
Advanced methodologies resolving dimensionality complications for autism neur...
cuic standard and advanced reporting.pdf
NewMind AI Weekly Chronicles - August'25-Week II
Machine learning based COVID-19 study performance prediction
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
Machine Learning_overview_presentation.pptx
Encapsulation theory and applications.pdf
Mobile App Security Testing_ A Comprehensive Guide.pdf
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
Empathic Computing: Creating Shared Understanding
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
Encapsulation_ Review paper, used for researhc scholars
Getting Started with Data Integration: FME Form 101
Assigned Numbers - 2025 - Bluetooth® Document
Digital-Transformation-Roadmap-for-Companies.pptx

groovy & grails - lecture 11

  • 1. Groovy: Efficiency Oriented Programming Lecture 11 Master Proteomics & Bioinformatics - University of Geneva Alexandre Masselot - summer 2011
  • 2. Agenda ‣ CRUD ‣ Integration tests ‣ Domain relationships ‣ Application configuration
  • 4. One domain based app ↔ one database
  • 5. One domain class ↔ one table
  • 6. One domain bean ↔ one table entry
  • 8. One bean operations: CRUD Action Create Read Update Delete
  • 9. One bean operations: CRUD Action Create Read Update Delete
  • 10. One bean operations: CRUD Action Create Read Update Delete
  • 11. One bean operations: CRUD Action Create Read Update Delete
  • 12. One bean operations: CRUD Action SQL Grails url Create INSERT create Read SELECT show Update UPDATE update Delete DELETE delete
  • 13. One bean operations: CRUD Action SQL Grails url Create INSERT create Read SELECT show Update UPDATE update Delete DELETE delete
  • 14. One bean operations: CRUD Action SQL Grails url Create INSERT create Read SELECT show Update UPDATE update Delete DELETE delete
  • 15. Person joe = new Person(params) ➙ bean but no database entry creation
  • 16. joe.save() ➙ insertion into table (only if valid bean - constraints)
  • 17. Validation ‣ Create only a valid bean ‣ 3 validation ways
  • 18. Validation ‣ Create only a valid bean ‣ 3 validation ways ‣ Check explicitly for validation joe.validate()
  • 19. Validation ‣ Create only a valid bean ‣ 3 validation ways ‣ Check explicitly for validation joe.validate() ‣ Save a catch exception joe.save(failOnError:true)
  • 20. Validation ‣ Create only a valid bean ‣ 3 validation ways ‣ Check explicitly for validation joe.validate() ‣ Save a catch exception joe.save(failOnError:true) ‣ Save a check for non-null return assert joe.save()
  • 21. Registered bean ⇔ joe.id != null
  • 22. Reading a bean from the database
  • 24. Dynamic finders: retrieve from constraints
  • 25. Dynamic finders (for single return) ‣ Domain class definition generate static methods def p = Person.findByUsername(‘lucky_luke’) def p = Person.findByFirstName(‘Lucky’) def p = Person.findByFirstNameAndLastName(‘Joe’, ‘Dalton’)
  • 26. Dynamic finders (for single return) ‣ Domain class definition generate static methods def p = Person.findByUsername(‘lucky_luke’) def p = Person.findByFirstName(‘Lucky’) def p = Person.findByFirstNameAndLastName(‘Joe’, ‘Dalton’) ‣ Multiple results => returns first (sorted on id) def p = Person.findByLastName(‘Dalton’)
  • 27. Dynamic finders (for single return) ‣ Domain class definition generate static methods def p = Person.findByUsername(‘lucky_luke’) def p = Person.findByFirstName(‘Lucky’) def p = Person.findByFirstNameAndLastName(‘Joe’, ‘Dalton’) ‣ Multiple results => returns first (sorted on id) def p = Person.findByLastName(‘Dalton’) ‣ findByXxxx efficient with unique:true fields
  • 28. Update ‣ Update: change fields values and save into database
  • 29. Update ‣ Update: change fields values and save into database 1. modify bean as usual
  • 30. Update ‣ Update: change fields values and save into database 1. modify bean as usual 2. validate/save as for creation
  • 32. Scaffolded controller hides CRUD operations
  • 33. Explicit controller ‣ It is possible to generate scaffold controller code generate-controller eop.lec11.twitter.Person
  • 34. Explicit controller ‣ It is possible to generate scaffold controller code generate-controller eop.lec11.twitter.Person ‣ PersonController.groovy write operation & test
  • 35. Explicit controller ‣ It is possible to generate scaffold controller code generate-controller eop.lec11.twitter.Person ‣ PersonController.groovy write operation & test ‣ For example, read: def show = { def personInstance = Person.get(params.id) if (!personInstance) { flash.message = "${message(code: 'default.not.found.message', .....)}" redirect(action: "list") } else { [personInstance: personInstance] } }
  • 36. Time to go back to test!
  • 37. Unit testing ↔ no dependency
  • 38. Integration testing ↔ more complex biotope
  • 39. Integration tests ‣ Resides under test/integration/ PersonIntegrationTests.groovy
  • 40. Integration tests ‣ Resides under test/integration/ PersonIntegrationTests.groovy ‣ Launched with test-app -integration
  • 41. Integration tests ‣ Resides under test/integration/ PersonIntegrationTests.groovy ‣ Launched with test-app -integration ‣ Results: - summary on the console output (count success/failures) - html files under target/tests-reports/html - plain text files under target/tests-reports/html - failure summary available - stdout/stderr accessible for each test case
  • 42. Faster grails command ‣ Launch command (<alt><ctrl>G) interactive
  • 43. Faster grails command ‣ Launch command (<alt><ctrl>G) interactive ‣ On the console, enter command test-app -integration
  • 44. Faster grails command ‣ Launch command (<alt><ctrl>G) interactive ‣ On the console, enter command test-app -integration ‣ Hit enter to relaunch last command
  • 45. Faster grails command ‣ Launch command (<alt><ctrl>G) interactive ‣ On the console, enter command test-app -integration ‣ Hit enter to relaunch last command ‣ After several commands, PermGenException can occur - terminate - relaunch interactive
  • 46. Grails integration testing cons ‣ Slower to execute than unit
  • 47. Grails integration testing cons ‣ Slower to execute than unit ‣ Test report is not integrated into eclipse
  • 48. Grails integration testing cons ‣ Slower to execute than unit ‣ Test report is not integrated into eclipse ‣ Use only when unit test not possible
  • 49. mockDomain: unit testing with domain class
  • 50. mockDomain ‣ It is possible to make some unit testing with domain
  • 51. mockDomain ‣ It is possible to make some unit testing with domain ‣ No real database is connected, but a fake layer
  • 52. mockDomain ‣ It is possible to make some unit testing with domain ‣ No real database is connected, but a fake layer ‣ In each method (not setup()) mockDomain(Person) mockDomain(Person, initialBeanList)
  • 53. mockDomain ‣ It is possible to make some unit testing with domain ‣ No real database is connected, but a fake layer ‣ In each method (not setup()) mockDomain(Person) mockDomain(Person, initialBeanList) ‣ All single domain CRUD (and more) operations possible
  • 54. mockDomain example void testDelete(){ //buildDaltonFamily() return a list of 4 Person mockDomain(Person, buildDaltonFamily()) assert Person.count() == 4 Person p=Person.findByUsername('joe_dalton') assertNotNull p p.delete() // we should only have 3 members left assert Person.count() == 3 p=Person.findByUsername('joe_dalton') assertNull p }
  • 55. mockDomain limits ‣ No explicit database operation (hibernate criteria, HQL) are possible
  • 56. mockDomain limits ‣ No explicit database operation (hibernate criteria, HQL) are possible ‣ Multiple domain class interaction are fully possible (cf. relationships)
  • 57. mockDomain limits ‣ No explicit database operation (hibernate criteria, HQL) are possible ‣ Multiple domain class interaction are fully possible (cf. relationships) ‣ Connection with data already entered in a database
  • 58. Hermit domain not very useful
  • 59. Need for relationships Twitter: Person ↔ Message
  • 61. Message domain create-domain-class Domain ‣ Just a text (String) and a commiter (Person) class Message { String text Person commiter static constraints = { text(size:1..140, blank:false) commiter(nullable:false) } }
  • 62. Message + Person ‣ Attach two messages to a user Person joe=Person.findByUsername('joe_dalton') new Message(text:'hello', commiter:joe).save() new Message(text:'world', commiter:joe).save()
  • 63. Message + Person ‣ Attach two messages to a user Person joe=Person.findByUsername('joe_dalton') new Message(text:'hello', commiter:joe).save() new Message(text:'world', commiter:joe).save() ‣ Look for message from joe Message.findAllByCommiter(joe)
  • 64. Message + Person ‣ Attach two messages to a user Person joe=Person.findByUsername('joe_dalton') new Message(text:'hello', commiter:joe).save() new Message(text:'world', commiter:joe).save() ‣ Look for message from joe Message.findAllByCommiter(joe) ‣ Not possible to access to message directly from joe bean - one solution: explicitly declare setCommiter(Person p) in Message.groovy that would add the message to a list in joe; - problem for deletion, save inconsistency...
  • 65. Define a one-to-many relationship
  • 67. One-to-many relationship ‣Message.groovy //Person commiter static belongsTo = [commiter:Person] ‣Person.groovy static hasMany = [messages: Message]
  • 68. One-to-many relationship (cont’d) ‣ Add a message: joe.addToMessages(new Message(text:‘hello world’)).save()
  • 69. One-to-many relationship (cont’d) ‣ Add a message: joe.addToMessages(new Message(text:‘hello world’)).save() ‣ Will execute the following actions - create a message with joe as commiter - save the message - add the message to joe’s list
  • 70. One-to-many relationship (cont’d) ‣ Access to the list joe.messages
  • 71. One-to-many relationship (cont’d) ‣ Access to the list joe.messages ‣ Deleting will cascade joe.delete() - all messages with joe as commiter will also be deleted
  • 72. Testing ‣ Test database consistency with two domain: integration testing // taken from MessageIntegrationTests.groovy // 4 Person are added in the setup() method public void testListMessagesUserDeletion(){ Person joe=Person.findByUsername('joe_dalton') Person averell=Person.findByUsername('averell_dalton') joe.addToMessages(new Message(text:'hello world')).save() joe.addToMessages(new Message(text:'i'm running')).save() averell.addToMessages(new Message(text:'i'm eating')).save() assert Message.count() == 3 assert Person.count() == 4 joe.delete() assert Person.count() == 3 //having deleted joe should delete all message related to joe assert Message.count() == 1 }
  • 73. Back to the web: 2 scaffolded controllers

Editor's Notes

  • #2: \n
  • #3: \n
  • #4: \n
  • #5: run-app generate the database\n
  • #6: Domain bean class generate a table from the member fields\n
  • #7: map one object &lt;-&gt; SQL statements\n
  • #8: \n
  • #9: \n
  • #10: \n
  • #11: \n
  • #12: \n
  • #13: \n
  • #14: \n
  • #15: \n
  • #16: \n
  • #17: \n
  • #18: \n
  • #19: \n
  • #20: \n
  • #21: \n
  • #22: \n
  • #23: \n
  • #24: id property is added by default to domain beans\nsetting the bean joe.id=123 is dangerous\n
  • #25: \n
  • #26: necessitate to know the beanId value\ntypically used with url show/id\n
  • #27: \n
  • #28: possible to configure sort on other condition in domain class definition\nunique:true =&gt; table index\n
  • #29: possible to configure sort on other condition in domain class definition\nunique:true =&gt; table index\n
  • #30: possible to configure sort on other condition in domain class definition\nunique:true =&gt; table index\n
  • #31: if not valid =&gt; bean remains the same in the database\n
  • #32: if not valid =&gt; bean remains the same in the database\n
  • #33: if not valid =&gt; bean remains the same in the database\n
  • #34: \n
  • #35: \n
  • #36: do not call generate-controller too early in development phase\n
  • #37: do not call generate-controller too early in development phase\n
  • #38: do not call generate-controller too early in development phase\n
  • #39: \n
  • #40: \n
  • #41: database\nsame situation ~ than with run-app\n
  • #42: PersonIntegrationTests instead PersonTests to avoid class name conflict\n
  • #43: PersonIntegrationTests instead PersonTests to avoid class name conflict\n
  • #44: PersonIntegrationTests instead PersonTests to avoid class name conflict\n
  • #45: \n
  • #46: \n
  • #47: \n
  • #48: \n
  • #49: \n
  • #50: \n
  • #51: \n
  • #52: \n
  • #53: \n
  • #54: \n
  • #55: \n
  • #56: \n
  • #57: see error groovy 1.6 on the storyboard\n
  • #58: \n
  • #59: \n
  • #60: \n
  • #61: \n
  • #62: \n
  • #63: This is not the correct way!\n
  • #64: This is not the correct way!\n
  • #65: \n
  • #66: \n
  • #67: \n
  • #68: grails will provide the mechanism for consistency\n
  • #69: \n
  • #70: \n
  • #71: addToMessages is implicitely created\n
  • #72: addToMessages is implicitely created\n
  • #73: \n
  • #74: \n
  • #75: \n
  • #76: \n
  • #77: \n
  • #78: \n