grailscollectionshqlgrails-orm

Order By Value In Collection With Database Query In Grails


My latest invention is a system where you can track waffles in real time at restaurants around the world.

To achieve this, I have a Waffle which has many Condiments, any of which may or may not be present on the Waffle. Waffle has the table number it's currently on, and belongs to a Restaurant which has many Names translated into different languages.

Technically, I need to get every Waffle where Waffle.shape == 'square' and order it by the Restaurant's Name where Waffle.Restaurant.Names.language == 'en' and display whether Condiment.present is true.

Restaurant.Names = ['language':'en', 'name':'Waffle House'],
                   ['language':'fr', 'name':'Le Waffle House'],
                   ['language':'de', 'name':'Das Waffle House']
Filtered by square shaped
============================

(Ascending order)
    V
Restaurant     Table#    Syrup    Butter    Mayo
---------------------------------------------------------
Denny's        42        Y        Y         N
Denny's        27        N        N         N
Denny's        11        Y        Y         N
IHOP           10        Y        N         N
IHOP           7         N        N         N
Waffle House   10        Y        Y         Y

Here's a simplified version of classes:

class Condiment {
    int condimentId
    boolean present
    Waffle waffle
    static belongsTo = [Waffle]
}

class Waffle {
    int waffleId
    int tableNumber
    String shape
    Restaurant restaurant
    static belongsTo = [Restaurant]
    static hasMany = [condiments:Condiment]
}

class Restaurant {
    int restaurantId
    static hasMany = [waffles:Waffle, names:Name]
}

class Name {
    String name
    String language
    static hasMany = [restaurants:Restaurant]
}

I'd like to do this in GORM if possible but HQL is acceptable too. This is with Grails 2.3. Keep in mind this is paginated because there are millions of Waffles in the world, if not more!


Solution

  • Criteria based:

    def waffles = Waffle.createCriteria().list(offset: 0, max: 100){
        eq('shape', 'square')
        restaurant{
            names{
                eq('language', 'en')
                order('name', 'asc')
            }
        }
        condiments{
            eq('present', true)
        }
    }
    

    HQL based:

    def query = """
                   select w from Waffles as w \
                   inner join w.restaurant as r \ 
                   inner join w.condiments as c \
                   inner join r.names as n \
                   where w.shape = :shape \
                   and n.language = :lang \
                   and c.present is true
                """
    
    def waffles = Waffle.executeQuery(query,[shape: 'square', lang: 'en', 
                                               max: 100, offset: 0])
    

    Will get you first 100 waffles.

    HQL based approach will be effective because restaurant, names and condiments will not be fetched eagerly which will be the case when Criteria is used as above.

    Change lang to 'fr' for French.