Grails Data Binding & criteria reuse

01 / Jul / 2011 by Uday Pratap Singh 1 comments

Data Binding in grails is something that I love alot. In most of the cases we look at the Binding with respect to some domain class but binding can be one of the best candidate for searching and filtration.
In my recent project we had a domain Class Article and the user could filter articles on different criteria. The page looks something like following

We had 3-4 such pages but with some extra states (Enum property) of article. So for doing this we created two CO classes, one for basic search properties like max, offset, order and sort and other for article related fields. So the CO goes like following

class SearchCO {
  Integer max = 10
  Integer offset = 0
  String sort = "id"
  String order = "asc"

  def searchCriteria = {
    order(sort, order)
  }
}

class ArticleSearchCO extends SearchCO {
  List<ArticleType> types  // This is Enum
  List<Long> styleIds
  List<Long> categoryIds
  String topic
  def searchCriteria = {
     and {
      if (topic) {
        ilike("topic", "%${topic}%")
      }

      if (categoryIds) {
        subCategory {
              inList("id", categoryIds)
          }
      }

      if (styleIds) {
        writingStyle {
             inList("id", styleIds)
         }
      }

      if (types) {
            inList("type", types)
        }
    }
    super.searchCriteria
  }
}

In our controller side we got the fully populated object that can be used for searching the different articles based on searching. So our controller side code was something like

def findWork = {ArticleSearchCO co ->
    List<Article> articles = authorService.findWork(co)
    render(template:"articles",model:[articles:articles,totalCount:articles.totalCount])
}

def currentWork = {ArticleSearchCO co ->
    List<Article> articles = authorService.currentWork(co)
    render(template:"articles",model:[articles:articles,totalCount:articles.totalCount])
}

As I already have the searching closures in my CO so the code in my service was something like

public List<Article> findWork(ArticleSearchCO co) {
    def articleCriteria = Article.createCriteria()
    Closure searchCriteria = co.searchCriteria
    searchCriteria.delegate = articleCriteria
    List<Article> articles = articleCriteria.list([max: co.max, offset: co.offset]) {
      eq("status", ArticleStatus.Unassigned)
      searchCriteria()
    }
    return articles
  }

In the same way for currentWork method I just changed the status i.e; ArticleStatus.InProgress. Thats how I handled the searching, filtering, pagination which was all Ajax. I tried to make my code as DRY as possible . There are still few things that I dont like about it one is so many if statements and other is delegating the searching criteria in each method. I think now with the support of namedQuery I can optimize the method.

Hope it helps
Uday Pratap Singh
uday@intelligrape.com

FOUND THIS USEFUL? SHARE IT

comments (1 “Grails Data Binding & criteria reuse”)

  1. ashipj

    Nice post. I was trying to apply the same methodology, in an application that i am working. I came across multiple limitation of this approach.

    1. Sorting wont work for fields in inner classes
    2. If you try to fetch distinct values, it would only return the projections specified and you wont get result as list of Objects.

    Reply

Leave a comment -