Criteria API hasmany Relationship的平均值

时间:2015-08-31 08:11:37

标签: grails criteria

我们有ShopArticles商店,想要添加评级系统。

我们的ShopArticle看起来像这样:

class ShopArticle { 
 String contUnit = 'STK', orderUnit = 'PCK'
 Double value, tax = 0.19
 String name, description, keyword
 String group1, group2, group3, articleNumber
 String producer  
 Boolean unlocked 

 static hasMany = [ratings: ShopArticleRating]
} 

评级看起来像这样:

class ShopArticleRating { 
String comment
int rating
ShopArticle shopArticle
User user 

static belongsTo = ShopArticle  
}

现在我们要过滤一个atricle的平均评分,所以我们做了这个:

        def shopArticleList = ShopArticleRating.createCriteria().listDistinct {
            projections {
                groupProperty("shopArticle")
            } 
        }
        def ids = []
        shopArticleList.each { shopArticle ->
            def sum = 0
            shopArticle.ratings.each {
                sum += it.rating
            }

            if ((sum / shopArticle.ratings.size()) >= filter.rating) {
                ids.add(shopArticle.id)
            }
        }

    List<ShopArticle> list = ShopArticle.createCriteria().list {
        if (ids.size() > 0) {
            'in'("id", ids)
        }
    }

有没有更好的方法来过滤平均评分?

也许是这样的:

List<ShopArticle> list = ShopArticle.createCriteria().list {
 createAlias('ratings','r')
 projections {
    groupProperty('r.rating')
 } 
 gt("r.rating",filter.rating)
}

2 个答案:

答案 0 :(得分:0)

如果是我,我会将一个averageRating属性添加到ShopArticle类本身。

计算在为ShopArticle添加/删除/更改评级时的平均值,并分配在每个评级条目/更改中进行数学计算的“成本”。十个人添加评分,你做10次数学运算。一千人做查询,你不做1000次数学计算。

显示平均评分只不过是在屏幕上显示另一个属性,过滤是微不足道的 - 查询数据时没有额外的工作(我认为可以安全地打赌会有更多的查询而不是添加评级)。 / p>

答案 1 :(得分:0)

试试这个:

ShopArticleRating.withCriteria {
    projections {
        avg("rating")
        groupProperty("shopArticle")
    }
}

这应该为您提供文章对象以及评分的平均值。

我无法测试相反的方式,但它应该是这样的:

ShopArticle.withCriteria {
    projections {
        ratings {
            avg("rating)
        }
        property("id")
    }
}

应该为您提供文章ID以及相应评级的平均值

另一种方法是编写自己的sql语法,让你绝对自由地返回你想要的一切。在这种情况下,寻找“grails HQL”。有时候,当我需要进行非常复杂的查询时,我会触摸边框。但在你的情况下,你应该是好的。