【问题标题】:Grails criteria projections - get rows countGrails 标准预测 - 获取行数
【发布时间】:2011-01-20 15:04:57
【问题描述】:

我有酒店实体:

class Hotel {
City city
}

现在,我需要指定城市的酒店数量。 可以这样实现:

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

但这是非常肮脏的方式。似乎有标准会更好,但我不知道如何实现它......

【问题讨论】:

    标签: java hibernate grails


    【解决方案1】:

    Dave is right,您可以使用countBy* 方法进行简单计数。如果您需要两个以上的条件,则必须恢复为 criteria apiHQL 或 SQL。需要两个以上的标准是很常见的,尤其是对于一个活跃且不断发展的代码库。

    这是一个示例,说明如何使用Criteria api 执行projections

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

    或者(更优雅地)您甚至可以使用 Criteria#count,如下所示:

    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
    }
    

    集成测试(使用build-test-data plugin

    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
        }
    }
    

    【讨论】:

    • 为简单起见,如何将标准放在一行中?我应该为每条语句添加分号 (;) 吗?
    • 相信你可以做到:Hotel.createCriteria().count { gt("stars", 2); eq("城市", 城市); eq("deleted", false) } 但我还没试过。
    • 如果我想知道哪些城市有不止一家酒店?
    • 看起来 GORM 条件查询中不支持“have”子句,但在 HQL 中。
    【解决方案2】:

    在域对象上有动态计数器和查找器:

    Hotel.countByCity(city)
    

    更多详情当然在user guide

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-21
      • 2012-11-25
      • 1970-01-01
      • 2013-01-22
      • 2023-03-13
      • 1970-01-01
      相关资源
      最近更新 更多