Search code examples
grailsif-statementnullablemultiple-domainscreatecriteria

Grails - createCriteria from if and else with null property


I am using Grails 2.3.4. I am trying to retrieve a domain object with specific criteria, however I have trouble getting around when the properties are null. Here is an example.

class Domain1 {
   int locationId
   Domain2 domain2
   Domain3 domain3
   ...
   static constraints = {
      locationId(nullable:false, blank:false, unique:false)
      domain2(nullable:true)
      domain3(nullable:true)
      ...
   }
}

class Domain2 {
   int locationId
   ...
   static constraints = {
      locationId(nullable:false, blank:false, unique:false)
      ...
   }
}

class Domain3 {
   int locationId
   ...
   static constraints = {
      locationId(nullable:false, blank:false, unique:false)
      ...
   }
}

The query is only suppose to return a single Domain1, if the locationId is valid in Domain1, and locationId valid in Domain2 if not null, and locationId valid in Domain3 if not null.

def getDomain1ById(Long sid) {
   return Domain1.createCriteria().get {
      idEq(sid)
      'in' ("locationId", Util.getUserAccessLocationList())
      // What I want to do is if(domain2 != null) check location
      or {
         isNull("domain2")
         domain2 {
            'in' ("locationId", Util.getUserAccessLocationList())
         }
      }
      // What I want to do is if(domain3 != null) check location
      or {
         isNull("domain3")
         domain3 {
            'in' ("locationId", Util.getUserAccessLocationList())
        }
      }
   }
}

What am I missing. The query works fine if domain2 and domain3 are not null


Solution

  • By default, Grails criteria queries use inner joins. To achieve the conditional behavior you're after, change to left joins:

    Domain1.createCriteria().get {
        createAlias('domain2', 'd2', CriteriaSpecification.LEFT_JOIN)
        createAlias('domain3', 'd3', CriteriaSpecification.LEFT_JOIN)
        idEq(sid)
        'in' ("locationId", locIds)
        or {
            isNull("domain2")
            'in' ("d2.locationId", locIds)
        }
        or {
           isNull("domain3")
           'in' ("d3.locationId", locIds)
        }
    }