## 5.4.1 Dynamic Finders

GORM supports the concept of dynamic finders. A dynamic finder looks like a static method invocation, but the methods themselves don't actually exist in any form at the code level.

Instead, a method is auto-magically generated using code synthesis at runtime, based on the properties of a given class. Take for example the `Book` class:

    class Book {
    	String title
    	Date releaseDate
    	Author author
    }
    class Author {
    	String name
    }

The `Book` class has properties such as `title`, `releaseDate` and `author`. These can be used by the findBy and findAllBy methods in the form of "method expressions":

    def book = Book.findByTitle("The Stand")book = Book.findByTitleLike("Harry Pot%")book = Book.findByReleaseDateBetween( firstDate, secondDate )book = Book.findByReleaseDateGreaterThan( someDate )book = Book.findByTitleLikeOrReleaseDateLessThan( "%Something%", someDate )

#### Method Expressions

A method expression in GORM is made up of the prefix such as findBy followed by an expression that combines one or more properties. The basic form is:

    Book.findBy([Property][Comparator][Boolean Operator])?[Property][Comparator]

The tokens marked with a '?' are optional. Each comparator changes the nature of the query. For example:

    def book = Book.findByTitle("The Stand")book =  Book.findByTitleLike("Harry Pot%")

In the above example the first query is equivalent to equality whilst the latter, due to the `Like` comparator, is equivalent to a SQL `like` expression.

The possible comparators include:

- `InList` - In the list of given values
- `LessThan` - less than the given value
- `LessThanEquals` - less than or equal a give value
- `GreaterThan` - greater than a given value
- `GreaterThanEquals` - greater than or equal a given value
- `Like` - Equivalent to a SQL like expression
- `Ilike` - Similar to a `Like`, except case insensitive
- `NotEqual` - Negates equality
- `Between` - Between two values (requires two arguments)
- `IsNotNull` - Not a null value (doesn't require an argument)
- `IsNull` - Is a null value (doesn't require an argument)

Notice that the last 3 require different numbers of method arguments compared to the rest, as demonstrated in the following example:

    def now = new Date()
    def lastWeek = now - 7
    def book = Book.findByReleaseDateBetween( lastWeek, now )books = Book.findAllByReleaseDateIsNull()
    books = Book.findAllByReleaseDateIsNotNull()

#### Boolean logic (AND/OR)

Method expressions can also use a boolean operator to combine two criteria:

    def books =
        Book.findAllByTitleLikeAndReleaseDateGreaterThan("%Java%", new Date()-30)

In this case we're using `And` in the middle of the query to make sure both conditions are satisfied, but you could equally use `Or`:

    def books =
        Book.findAllByTitleLikeOrReleaseDateGreaterThan("%Java%", new Date()-30)

At the moment, you can only use dynamic finders with a maximum of two criteria, i.e. the method name can only have one boolean operator. If you need to use more, you should consider using either Criteria or the HQL.

#### Querying Associations

Associations can also be used within queries:

    def author = Author.findByName("Stephen King")def books = author ? Book.findAllByAuthor(author) : []

In this case if the `Author` instance is not null we use it in a query to obtain all the `Book` instances for the given `Author`.

#### Pagination & Sorting

The same pagination and sorting parameters available on the list method can also be used with dynamic finders by supplying a map as the final parameter:

    def books =
      Book.findAllByTitleLike("Harry Pot%", [max:3,
                                             offset:2,
                                             sort:"title",
                                             order:"desc"])