Кризисные прогнозы Грайла - подсчет строк

У меня есть гостиничный объект:

class Hotel {
City city
}

Теперь мне нужно посещать отели с данным городом. Это можно сделать следующим образом:

def hotels = Hotel.findAllByCity(city)
def cnt = hotels.size()

Но это очень грязный способ. Похоже, что с критериями было бы лучше, но я понятия не имею, как его реализовать...

Ответы

Ответ 1

На объектах домена есть динамические счетчики, а также искатели:

Hotel.countByCity(city)

Подробнее в руководство пользователя, конечно

Ответ 2

Дейв прав, что вы можете использовать методы countBy * для простых считая. Если вам нужно больше двух критериев, вам придется вернуться к критериям api, HQL или SQL. Очень часто требуется более двух критериев, особенно с активной и развивающейся кодовой базой.

Вот пример того, как использовать Criteria api для projections:

def c = Hotel.createCriteria()

def hotelCount = c.get {
    projections {
        count('id')
    }
    gt("stars", 2)          
    eq("city", city)            
    eq("deleted", false)

}

В качестве альтернативы (более элегантно) вы даже можете использовать критерий #, как показано ниже:

def c = Hotel.createCriteria()

def hotelCount = c.count {
    gt("stars", 2)          
    eq("city", city)            
    eq("deleted", false)

}

Просто ради полноты:

class Hotel {
    City city
    Boolean deleted = false
    Integer stars
}

class City {
    String name
}

Тестирование интеграции (с помощью плагин для построения тестовых данных)

import grails.test.*

class HotelTests extends GrailsUnitTestCase {

    void testCriteria() {
        City city1 = City.build(name:'one')
        assertNotNull(city1)
        City city2 = City.build(name:'two')
        assertNotNull(city1)

        Hotel fiveStarHotel= Hotel.build(city:city1, deleted:false, stars:5)
        assertNotNull(fiveStarHotel)

        Hotel hotelInCity2 = Hotel.build(city:city2, deleted:false, stars:5)
        assertNotNull(hotelInCity2)

        Hotel deletedHotel = Hotel.build(city:city1, deleted:true, stars:5)
        assertNotNull(deletedHotel)

        Hotel threeStarHotel = Hotel.build(city:city1, deleted:false, stars:3)
        assertNotNull(threeStarHotel)

        Hotel oneStarHotel = Hotel.build(city:city1, deleted:false, stars:1)
        assertNotNull(oneStarHotel)

        def c = Hotel.createCriteria()

        def hotelCount = c.get {
            projections {
                count('id')
            }
            gt("stars", 2)          
            eq("city", city1)           
            eq("deleted", false)

        }
        assertEquals(2, hotelCount) //should only find the 5 and 3 star hotel

        def c2 = Hotel.createCriteria()
        hotelCount = c2.count {
            gt("stars", 2)          
            eq("city", city1)           
            eq("deleted", false)

        }
        assertEquals(2, hotelCount) //should only find the 5 and 3 star hotel
    }
}