Verifying Grails GORM Dynamic Finders and Their Generated SQL
A step‑by‑step guide to create a Grails application, invoke dynamic finders, and confirm the SQL they produce matches expectations.
12 Dec 2025, 13:16 UTC

Desired outcome
Confirm that Grails GORM dynamic finders are working correctly in a test application and that the SQL they generate matches the intended query (appropriate WHERE clauses, no unnecessary joins).
Prerequisites
- Java Development Kit (JDK) 11 or later installed.
- Grails 3.x or 4.x installed (the guide uses Grails 3.3.11, but any 3.x/4.x version works).
- A terminal or command prompt with
grailson the PATH. - Optional: an IDE (IntelliJ IDEA, VS Code) for easier code navigation.
Procedure
- Create a new Grails application
grails create-app dynamic-finder-demo cd dynamic-finder-demoThis creates a standard Grails project with GORM as the default persistence layer.
- Define a domain class
Create
grails-app/domain/demo/Book.groovywith a few properties:package demo class Book { String title String author Double price static constraints = { title blank: false author blank: false price min: 0.0 } } - Add bootstrap data
Edit
grails-app/init/BootStrap.groovyto insert a couple of rows when the app starts:class BootStrap { def init = { servletContext -> new Book(title: 'Grails in Action', author: 'Dierk König', price: 39.99).save(flush: true) new Book(title: 'Effective Java', author: 'Joshua Bloch', price: 45.00).save(flush: true) new Book(title: 'Learning Groovy', author: 'Ken Kousen', price: 29.95).save(flush: true) } def destroy = {} } - Enable SQL logging
To see the generated SQL, add a logger for Hibernate SQL in
grails-app/conf/logback.groovy(or log4j.properties for older versions):logger('org.hibernate.SQL', DEBUG, ['STDOUT'], false) logger('org.hibernate.type.descriptor.sql.BasicBinder', TRACE, ['STDOUT'], false) - Run the application
grails run-appWait for the server to start (default port 8080). The bootstrap will insert the three books.
- Invoke a dynamic finder from a controller or service
Create a simple controller to test the finder:
package demo class BookController { def index() { // Example: find books with title like 'Grails%' and price between 30 and 50 def results = Book.findByTitleLikeAndPriceBetween('Grails%', 30.0, 50.0) render "Found ${results.size()} books: ${results*.title}" } }Access
http://localhost:8080/book/indexin a browser or via curl. - Check the console output for SQL
Look for lines similar to:
Hibernate: select this_.id as id1_0_0_, this_.author as author2_0_0_, this_.price as price3_0_0_, this_.title as title4_0_0_ from book this_ where this_.title like ? and this_.price between ? and ?Verify that the WHERE clause contains exactly the conditions you specified (title LIKE and price BETWEEN) and that no extra joins appear.
- Validate the result
The response should show "Found 1 books: [Grails in Action]". If you see a different count or unexpected titles, re‑examine the finder method name and the data in the bootstrap.
Expected checks
- The application starts without errors.
- The console logs a single SQL SELECT statement with the correct WHERE clause.
- The HTTP response returns the expected number of matching domain instances.
Recovery options
If the test fails or you wish to clean up:
- Stop the running Grails process (Ctrl+C in the terminal).
- Remove the project directory:
rm -rf dynamic-finder-demo(or delete the folder via your OS file explorer). - Re‑run the
grails create-appcommand to start fresh.
Limitations and practical tips
- Dynamic finders are convenient but can generate inefficient SQL if used on unindexed columns or inside loops, leading to N+1 query problems. For bulk operations consider criteria queries or HQL.
- Method names are limited by Hibernate’s naming length; avoid extremely long chains or special characters in property names.
- When using asynchronous GORM (requires the
asyncplugin), the finder returns aPromise-like object; you must handle it withwhenorthencallbacks. - Always verify the generated SQL in development; if you see unexpected joins or missing conditions, refactor to a explicit HQL or Criteria query.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.