Jesús Iglesias
Jesús Iglesias

Reputation: 140

Criteria - DetachedCriteria in Grails

FIRST QUESTION:

I have the following domain class in my app:

class Test {

 ...
 String name
 static hasMany = [evaluationsTest: Evaluation]
 ...

}

class Evaluation {
 ...
 String testName
 Float testScore
 ...
}

I need to obtain the number of evaluations between a range of scores (example: evaluations with scores between 7-8 ) of a specific test.

With a criteria I can obtain it correctly:

def criteria = Test.createCriteria()
def example = criteria.list {
   eq 'name', params.test
   evaluationsTest {
      ge("testScore", 7 as Float)
      lt("testScore", 8 as Float)
   }
   projections {
      count()
   }
}

But I want to know a async search and for this reason I want to use a DetachedCriteria but it does not work.

DetachedCriteria detached = Test.where {
   name == params.test
   evaluationsTest {
      ge("testScore", 7 as Float)
      lt("testScore", 8 as Float)
   }
   .projections {
      count()
   }
} as DetachedCriteria

def result = detached.async.list()

EDITED: Solved with withCriteria() method.

SECOND QUESTION:

Besides, I have another doubt. I need to parallelize this code. How can I do the each fragment? I used to task but sometimes works and other times appears the error: Array Index Out of Bounds Exception

// Rows
def rows = []
def addRow = { name, value ->
    rows << [c: [[v: name], [v: value]]]
}
// Add departments
departments.each { department ->
    addRow(department.name, department.users.size())
}
def UDData = [cols: cols, rows: rows]

With this code (tasks), I obtain: Array index out of bounds

List queriesToExecute = []

// Add departments - Asynchronous/Multi-thread
departments.each { department ->
    def departmentTask = tasks {
        rows << [c: [[v: department.name], [v:department.users.size()]]]
     }
     queriesToExecute << departmentTask
 }
 waitAll(queriesToExecute)

Upvotes: 1

Views: 2420

Answers (1)

Emmanuel Rosa
Emmanuel Rosa

Reputation: 9895

One reason your query may be failing is because you're creating a where query instead of a criteria query, and where queries do not support projections very well. They work... but only sometimes. And you'd have to define them outside of the query, like so:

DetachedCriteria detached = Test.where {
   name == params.test
   evaluationsTest {
      ge("testScore", 7 as Float)
      lt("testScore", 8 as Float)
   }   
}.projections {
      count()
} as DetachedCriteria

But, you don't actually need a DetachedCriteria to perform an async query. You can do it with a criteria query:

def promise = Test.async.withCriteria() {
   eq 'name', params.test
   evaluationsTest {
      ge("testScore", 7 as Float)
      lt("testScore", 8 as Float)
   }
   projections {
      count()
   }
}

def result = promise.get()

Collecting the departments concurrently

Here's an example of using GPars to collect the department data concurrently, without side-effects:

import static groovyx.gpars.GParsPool.withPool

def rows

withPool {
    rows = departments.collectParallel { department ->
        [c: [[v: department.name], [v:department.users.size()]]]
    }
}

def UDData = [cols: cols, rows: rows]

This is using fork-join. So the Closure is executed concurrently, and then the results are joined together.

Upvotes: 1

Related Questions