【问题标题】:Compare associations between domain objects in Grails比较 Grails 中域对象之间的关联
【发布时间】:2010-04-08 00:30:45
【问题描述】:

我不确定我是否是最好的方法,但我会尝试解释我想要做什么。

我有以下域类

类用户{ 静态 hasMany = [目标:目标] }

所以每个用户都有一个目标对象列表。我希望能够获取一个用户实例并返回 5 个用户,他们的目标列表中匹配的目标对象(与实例)数量最多。

有人可以解释一下我会怎么做吗?

【问题讨论】:

  • 那么你想取一个用户对象,根据某个规则找到other个匹配的用户对象?
  • 正确,通过匹配每个用户目标列表中的目标对象。
  • “匹配”是什么意思?我认为它是根据某些标准评分的。还是我想太多? :)

标签: grails groovy


【解决方案1】:

实现此目的最简单、最有效的方法是使用纯 SQL。假设你有这些表

users      [id]
goals      [id, description]
user_goals [user_id, goal_id]

您可以使用以下查询来做您需要的事情:

set @userId=123;
select user_id, count(*) as matched from user_goals
where user_id!=@userId
  and goal_id in (select ug.goal_id from user_goals ug where ug.user_id=@userId)
group by user_id order by matched desc limit 5;

这需要一个用户 id 并返回一个具有匹配目标的其他用户列表,按匹配数排序。用GoalService 把它包起来,你就完成了!

class GoalService {
  def findUsersWithSimilarGoals(user) {
    // ...
  }
}

也可以使用条件或 HQL 执行此操作,但使用此类查询通常更容易使用 SQL。

【讨论】:

  • 美丽 - 谢谢。我确实将 count(*) 更改为 count(distinct goal_id) 以便不计算多个目标
  • 不用担心。很高兴您发现它很有用。
【解决方案2】:

如果您正在寻找一个简单的匹配,也许最简单的方法是为每个目标执行 findAll,然后计算每个其他用户出现的结果数:

Map user2Count = [:]
for (goal in myUser.goals){
    for (u in User.findAllByGoal(goal)){
         def count = user2Count.containsKey(u) ? user2Count.get(u) : 0
         count++
         user2Count.put(u, count)
    }
}
// get the top 5 users
def topUsers = user2Count.entrySet().sort({ it.value }).reverse()[0..5]

这可能太慢了,这取决于您的需要,但它很简单。如果许多用户共享相同的目标,那么您可以缓存 findAllByGoal 的结果。

【讨论】:

  • 离题:正是这种情况让我希望 groovy 具有 perl 风格的自动激活功能,这样我们就可以在散列中增加一个值,而无需检查密钥是否已经存在。在 Perl 中,循环中的代码就是 $user2Count{u}++。
  • 我不知道 - autovivification 有时会在后面咬我 :) 但是是的,它确实有它的用途!我想知道用这种语言实现会有多难。
  • 这个旧的邮件列表线程:old.nabble.com/Multidimensional-maps-td19615874.html 有一些有趣的事情要说 - 它看起来很容易实现。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-22
  • 1970-01-01
  • 1970-01-01
  • 2016-10-29
相关资源
最近更新 更多