Search code examples
javagrailsgroovyclosurescriteria

Refactor closure criteria to fix maximum number of expressions in a list is 1000


I've found the following piece of code in an application I have to maintain

 def addCriteriaClosure = { criteriaList ->
   criteriaList.inList('id', paketInstance.dateien.id)
 }
 def criteria = Datei.createCriteria()
 def result = criteria.list() {
   addCriteriaClosure.call(criteria)
 }

Sadly, this call results in the following error:

java.sql.SQLSyntaxErrorException: ORA-01795: maximum number of expressions in a list is 1000

Fact is that paketInstance.dateien contains more then 1000 rows / items. To avoid this error I've tried the following approach:

def addCriteriaClosure = { criteriaList ->
  paketInstance.dateien.asList().collate(999).each {
    criteriaList.inList('id', paketInstance.dateien.asList().collate(999).id)
  }
}

but this results in this error:

java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.lang.Long

I know that the solution is to use the collate(999) operation, but I don't know how to combine it with the initial approach to get the expected result.

Edit #1

Unfortunatly I can not edit this part of the implementation:

 def criteria = [Type].createCriteria()
 def result = criteria.list() {
   addCriteriaClosure.call(criteria)
 }

Where the concrete type gets passed in to the method. I only can edit the definition of the addCriteriaClosure For example:

 def addCriteriaClosure = { criteriaList ->
   criteriaList.inList('id', paketInstance.dateien.id)
 }

Edit #2

When I design my criteria closure like following

def l = paketInstance.dateien.id.toList().collate(999)
        def addCriteriaClosure = { criteriaList ->

            l.each {
                a -> criteriaList.inList("id", a.toList())
            }
        }

Hibernate creates an SQL-Statement which splits the lists into to seperate in WHERE clauses. But the problem is that these two clauses are linked with an AND. To get the right result I need the OR for the two lists, not the AND in the generated sql

produced SQL:

 select this_.id as id51_0_, this_.version as version51_0_, this_.aktualisiert_am as aktualis3_51_0_, this_.name as name51_0_, this_.nummer as nummer51_0_, this_.pfad as pfad51_0_, this_.status as status51_0_, this_.typ as typ51_0_ from datei this_ where this_.id in (?, ?, ?, ?, ?, ?....)  and this_.id in (?, ?, ?, ?, ?, ?, ?....)

So Instead of and this_.id in I need or this_.id in


Solution

  • Found a solution

    def collatedFileList = paketInstance.dateien.id.toList().collate(999)
            def addCriteriaClosure = { criteriaList ->
                criteriaList.or {
                    collatedFileList.each {
                        l -> criteriaList.inList("id", l.toList())
                    }
                }
            }
    
    1. Resolves the problem I had to face
    2. Learned a lot about the Closure / Criteria thing