Is there a 'not in' equivalent in GORM? - grails

Is this possible to convert in createCriteria()?
SELECT * FROM node WHERE (node.type = 'act' AND nid NOT IN (SELECT nid FROM snbr_act_community)) LIMIT 10
I know there's a 'in' operator and here's what I have so far:
def c = VolunteerOpportunity.createCriteria()
def matchingActs = c.list {
node {
eq('type', 'act')
}
maxResults(10)
}
Just want to see if this is possible. Otherwise, I guess this is possible in HQL right?

thanks Sammyrulez for the code. got an idea from that. tested it but it didn't work. i fixed it and here's the final working code:
def ids = [14400 as long, 14401 as long]
def c = VolunteerOpportunity.createCriteria()
def matchingActs = c.list {
node {
eq('type', 'act')
not { 'in'(ids) }
}
maxResults(10)
}
now i know how to use 'not' operator. thanks a lot!

not tried it myself but looking at the Grails doc and hibernate api you create nodes on this builder map with the static methods found in the Restrictions class of the Hibernate Criteria API 1. So something like
def c = VolunteerOpportunity.createCriteria()
def matchingActs = c.list {
node {
not(in('propertyName', ['val1','val2']))
}
maxResults(10)
}
Since you chain the in method (that returns a Criterion) with the not method (that takes a Criterion as argument and returns a negated version)

this is the solution :
def resultat=EnteteImputationBudgetaire.createCriteria().get{
between("dateDebutPeriode", dateDebut, dateFin)
and{ eq 'natureImputationBudgetaire','FONCTIONNEMENT' }
maxResults(1)
}
def resultat2=ParametragePlanBudgetaire.createCriteria().list() {
like('composantBudgetaire','6%')
if(resultat?.details) {
not {
'in'('composantBudgetaire',resultat?.details?.imputationBudgetaire)
}
}
}

According to Grails documentation about creating criteria here, you can use something like this:
not {'in'("age",[18..65])}
In this example, you have a property named "age" and you want to get rows that are NOT between 18 and 65. Of course, the [18..65] part can be substituted with any list of values or range you need.

Just remembering: in this case you don't have to use parenthesis and you can use inList, for example:
not { inList 'age',[18..65] }

Related

gorm .where with like

New to groovy, grails.
I have the following query where I want to match a few paramater exactly to as passed(eq), but for one, which I want to using a 'like'
if (params.ret_code) {
ret_cod = params.ret_code+"%"
}
def srchresults = DmnObj.where {
if (params.doc_num) { doc_num == params.doc_num.trim() } //works as expected
//How do I do this????
if (params.retn_code) { retn_code like ret_cod }
}
Tried this, but in-vain.
how do I set retn_code with a like?
Thank you!
This is how you can do this
// case sensitive like
def result = Domain.where {
fieldName ==~ "value"
}
// case insensitive like
def result = Domain.where {
fieldName =~ "value"
}
Remember to prefix, suffix or both the value with %. For more about where queries https://grails.github.io/grails-doc/latest/guide/GORM.html#whereQueries
You can do like this:
var feel []DB.Feelings
db.Where("column_name LIKE ?", "%"+yourText+"%").Limit(your_limit).Offset(your_offset).Find(&feel)
column_name is your column name
Limit and Offset are not required
You can do like this:
def result = DomainClass.where{
like('fieldName', '%'+myVariable+'%')
}
I suggest you have a look at the Grails documentation (section Domain Class Usage): you will find several interesting ways to filter your domain class objects as for example HQL queries or findAllBy* dynamic methods.

constructing Grails/Groovy where query in run-time

Is it possible to construct such query in run-time in grails/groovy ?
Let's say I have:
def query = Person.where {
age in 18..65
}
and in run-time I wanna add weight to it as :
def query = Person.where {
age in 18..65
weight in 100..200
}
possible ?
I would use Criteria Queries instead. They allow you to dynamically construct queries like you want very easily. For example, you could create a criteria like this:
def result = Person.createCriteria {
'in'("age", [18..65])
if (params.includeWeight) {
'in'("weight", [100..200])
}
}.list()
Person.where is a method that takes a Closure as argument. A feature that closures have is composition. Here's an example from Groovy Goodness:
def convert = { new Expando(language: it) }
def upper = { it.toUpperCase() }
// Composition.
def upperConvert = convert << upper
So you can do something like:
def defaultWhere = {
age in 18..65
}
if(someRuntimeTest) {
defaultWhere << {
weight in 100..200
}
}
Person.where(defaultWhere)

Grails criteria builder

I have the folowing:
class Store{
String name
}
class Shop{
String name
Store store
}
My criteria builder:
def c = Shop.createCriteria()
def results = c.list {
like("name", "Harrods")
like("store.name", "McDonals")
}
I'm sure this is invalid cause i'v tested it. How can i manage to use criteriaBuilder and do this: like("store.name", "McDonals")?
Looking forward to get any help,
John
Since you're querying an association, try:
def results = c.list {
like('name', 'Harrods')
store {
like('name', 'McDonals')
}
}
This will do an conjoined query between name and store.name.
Check out the documentation Looks like you need to use a % for your like clause.

How can I avoid redundancy in nearly identically criteria?

Imagine I have the following query:
def result = Test.createCriteria().list(params) {
// image here a lot of assocs, criterias, ...
}
In many cases you need the row count of the query above, e.g. list actions of many controllers.
def resultTotal = Test.createCriteria().list(params) {
// Imagine here a lot of assocs, criterias, ...
// Change to the criteria above is only the projection block
projections { rowCount() }
}
How can I avoid this?
You can:
Extract the Criteria creation to a conditional factory/builder method;
Use named queries;
Use named query parameters (and Groovy code!) to alter the query "on the fly", like:
.
static namedQueries = {
byLocation { Location location ->
if (location) {
... // some more criteria logic
}
}
}
If you aren't paginating the results of the query, you can simply do the following after the first query is invoked:
def resultTotal = result?.size()
For the same set of query being used at many places, I create them as a closure and change its delegate to the criteria in question.
For example :
def query = {
projections{
rowCount()
}
eq('type', myType)
}
def criteria = Customer.createCriteria()
query.delegate = criteria
myType = CustomerType.guest
List records = criteria.list(params) {
query()
}
I use totalCount like this:
def list() {
def myInstanceList = MyInstance.createCriteria().list(params){
eq('name', params.name)
}
[myInstanceList: myInstanceList, myInstanceListTotal: myInstanceList.totalCount]
}

Can I append a closure to another in Groovy?

I have two very similar methods in Grails, something like "calculate statistics by os" and "calculate statistics by browser" - effectively both prepare some things, then run a similar query on the DB, then do things with the results. The only part where the methods differ is the query they run in the middle of my method -
def summary = c.list {
eq('browser', Browser.get(1)) // OR eq('os', OS.get(1))
between('date', dates.start, dates.end)
}
It occurred to me that the ideal way to refactor it would be to pass in the first line of the closure as a method parameter. Like
doStats (Closure query) {
...
def summary = c.list {
query
between('date', dates.start, dates.end)
}
}
I tried this but "query" gets ignored. I tried query() instead but then the query clause is executed where defined, so this doesn't work either. I suppose I could just pass the whole closure as a parameter but that seems wrong - the query might also get more complicated in future.
Anyone have any better ideas?
I found leftShift operator useful for composing closure from two separate ones. What you can do is:
Closure a = { /*...*/ }
Closure b = { /*...*/ }
Closure c = a << b
Take a look at this example:
def criteria = {
projection Projections.distinct(Projections.property('id'))
and {
eq 'owner.id', userDetails.id
if (filter.groupId) {
eq 'group.id', filter.groupId
}
}
}
List<Long> ids = Contact.createCriteria().list(criteria << {
maxResults filter.max
firstResult filter.offset
})
Integer totalCount = Contact.createCriteria().count(criteria)
What you can see here is that I'm creating a criteria for listing ant counting GORM objects. Criterias for both cases are almost the same, but for listing purposes I also need to include limit and offset from command object.
You're using the criteria DSL which might be different than plain groovy closures.
To do what you're asking, you can use the method described here -
http://mrhaki.blogspot.com/2010/06/grails-goodness-refactoring-criteria.html
and put your query in to private method.
The more elegant solution for this is to use named queries in grails -
http://grails.org/doc/latest/ref/Domain%20Classes/namedQueries.html
Look at the
recentPublicationsWithBookInTitle {
// calls to other named queries…
recentPublications()
publicationsWithBookInTitle()
}
example -
Not sure about with the Grails Criteria builder, but with other builders, you can do something like:
doStats (Closure query) {
def summary = c.list {
query( it )
between('date', dates.start, dates.end)
}
}
And call this via:
def f = { criteria ->
criteria.eq( 'browser', Browser.get( 1 ) )
}
doStats( f )
If not, you're probably best looking at named queries like tomas says

Resources