Grails criteria query retruing duplicate instances
Asked Answered
N

4

6

I have a domain class called Order and that class has hasMany relation with Item class. When I am querying for the list of orders with certain restrictions I am getting as many instances of Order as there are items.

So for example Order instance has say references to 3 instances of Item then , criteria call on Order is returning 3 duplicate instances of Order. I am not sure but if it's worth mentioning that the domain class Order has fetchMode set to "eager".

I am really puzzled with what's going on there. Any help in this regard will be greatly appreciated. Snippet of code is attached:

def clazz = "cust.Order"
def criteria = clazz.createCriteria()
        println("clazz == "+Order.list())// returning correct data i.e unique instance of order
        def filter = {
                    // trimmed down all filtering criteria for debugging
            }//close filter
        List results = criteria.list(max:params?.max,offset:params?.offset,filter)
            results.each{Object data->
                println(data.getClass())
            }
        println("results == "+results)

Thanks again

Northman answered 19/10, 2011 at 12:26 Comment(0)
D
2

Criteria API is just a wrapper for constructing a SQL query. In your case, the query in question has JOINs in it (because of the eager fetching), and returns a cartesian product of Orders and their matching Items. Each row returned is included in results as a separate Order instance.

The easiest way to remove duplicates is to put all the results in a Set, like this:

def resultSet = new HashSet()
resultSet.addAll(results)
println("results == " + resultSet)
Disregard answered 19/10, 2011 at 12:38 Comment(1)
This worked but is there any better way to solve this ? Like changing fetch mode during query or any thing like that ?Northman
E
5

One solution is to use this inside your query:

resultTransformer org.hibernate.Criteria.DISTINCT_ROOT_ENTITY
Elisabethelisabethville answered 5/7, 2013 at 12:15 Comment(0)
M
4

If you call criteria.listDistinct instead of criteria.list duplicates will be eliminated

Mccallum answered 19/10, 2011 at 12:53 Comment(2)
It should be noted that this can change the type of the results from a ResultSet to a List of Domain objects (breaks pagination in some cases).Carolynncarolynne
You cannot added params like max or offset with listDistinct (The listDistinct() method does not work well with the pagination options maxResult and firstResult. If you need distinct results with pagination, we currently recommend that you use HQL), at least in grails 2.x or belowWinther
D
2

Criteria API is just a wrapper for constructing a SQL query. In your case, the query in question has JOINs in it (because of the eager fetching), and returns a cartesian product of Orders and their matching Items. Each row returned is included in results as a separate Order instance.

The easiest way to remove duplicates is to put all the results in a Set, like this:

def resultSet = new HashSet()
resultSet.addAll(results)
println("results == " + resultSet)
Disregard answered 19/10, 2011 at 12:38 Comment(1)
This worked but is there any better way to solve this ? Like changing fetch mode during query or any thing like that ?Northman
T
0

You could also use dynamic finders, as in Order.findAllBy* .Depending on how complicated your filter is, this could be easy or tough :)

Temperament answered 19/10, 2011 at 13:15 Comment(1)
My filter is quite complicated and very dynamic too, I don't think findBy will work in this case. Filter applies to nested objects as well. That's one of the reason I decided to use criteria over native SQLNorthman

© 2022 - 2024 — McMap. All rights reserved.