查询的 Grails HQL 表示

Grails HQL representation of a query

我无法在 HQL 中表示以下 MySQL 查询

SELECT t1.id as user_id, t2.id as follow_id
FROM user t1
INNER JOIN follows t2 ON 
    (t2.follower_id = <user id> AND t2.followee_id = t1.id) OR
    (t2.follower_id = t1.id AND t2.followee_id = <user id>)
WHERE t1.active = true
ORDER BY t1.id

你能帮我解决这个问题吗?

谢谢!

编辑:

到目前为止,我已经尝试了以下 HQL 查询,但它无法 return 正确的数据:

SELECT t1
FROM User t1
JOIN t1.follows t2
JOIN t2.follower follower
JOIN t2.followee followee
WHERE (follower.id = :usr AND followee.id = t1.id) OR
    (follower.id = t1.id AND followee.id = :usr) 
    AND t1.active = true
ORDER BY t1.id

想法是我有两个表:

User table:
+------+--------+-------------+
|  id  | name   | last_name   |
+------+--------+-------------+
| 1    | Jhon   | Doe         |
| 2    | Jane   | Doe         |
| 3    | Alfred | Hitchcock   |
+------+--------+-------------+
Follows table:
+------+-------------+-------------+
|  id  | follower_id | followee_id |
+------+-------------+-------------+
| 1    | 1           | 3           |
| 2    | 3           | 2           |
| 3    | 2           | 1           |
+------+-------------+-------------+

我需要的是,例如,获取所有关注或被关注的用户的名字和姓氏,比方说,用户id 1。

我发布的 SQL 查询正是这样做的,但我似乎无法在 HQL 中复制相同的行为。

第二次编辑: 我的简化域名 类 是:

class User {
    String name
    String lastName
    ...
    static hasMany = [ follows: Follows ]
    static mappedBy = [ follows: 'follower' ]
}

还有...

class Follows {
    User Followee
    ...
    static belongsTo = [follower: User]
}

编写 HQL 查询时要记住的重要一点是 域 class 加入(HQL 处理域 classes,而不是 tables) 完全依赖于域 class 关联。换句话说,关联实际上创建了(内部)联接,但 HQL 允许您更改联接 type(LEFT OUTER、RIGHT OUTER 和 Cartesian)。请参阅我的 from clause 文章。

我试图从您的 HQL 和 table 描述中获取您的域 class 关联,但它不匹配。但这里有另一种方法。

领域模型

领域模型非常简单。有一个 User class 包含与自身的 一对多 关联(但它不是自连接,稍后您会看到) .

class User {
    String name
    String lastName

    static hasMany = [followees: User]  
}

假设您有一个 User 实例。

def user = User.get(1)

user.followees 包含 User 后跟 user

Table 架构

有了这样的域模型,tables 看起来像这样:

用户table

+------+--------+-------------+
|  id  | name   | last_name   |
+------+--------+-------------+
| 1    | John   | Doe         |
| 2    | Jane   | Doe         |
| 3    | Alfred | Hitchcock   |
+------+--------+-------------+

user_followees table

+-----------+-------------------+
|  user_id  | followees_user_id |
+-----------+-------------------+
| 1         | 2                 |
| 3         | 1                 |
+-----------+-------------------+

显示的数据表明:

  1. John Doe 关注 Jane Doe。
  2. Jane Doe 其次是 John Doe。
  3. Alfred Hitchcock 关注 John Doe。
  4. John Doe 其次是 Alfred Hitchcock。

这个简单的一对多 关联可以用来模拟被称为跟随 的双向关系。同样可以用两个一对多关联来完成,这将简化查询但使数据维护复杂化。使用此模型,双向 跟随 关系由单个 user.addToFollowee()user.removeFromFollowee().

维护

正在查询

使用我描述的域模型,您可以查询 followees 和 followers。给定 user...

def followees = user.followees // <-- contains Jane Doe

def followers = User.executeQuery 
    'SELECT u FROM User as u INNER JOIN u.followees as followee WHERE followee = :user',
    [user: user] // <-- contains Alfred Hithchcock

def following = followees + followers

请注意 GORM/Hibernate 不支持 SQL 的 UNION 子句,因此您需要两个查询。有关 GORM 等效于 where 子句的更多详细信息,请参阅我的 where clause 文章。

关注者

也可以使用 wherecriteria 查询来获取关注者:

def followers = User.where { followees.id == user.id }.list()
def followers = User.withCriteria { followees { eq 'id', user.id } }

只是为了简单起见,因为我只是在读取数据,所以我最终使用了 Groovy SQL,它被 Grails 接受并且它本身接受普通的 SQL 查询 I包含在我原来的 post 中(并且不需要匹配任何特定的域模型,在这种情况下对我来说是一大优势)

这里有一个link到JavaDoc,我专门用rows(String sql, Map params)方法定义来查询de DB和return数据我在找。

为了在 Grails 中使用 groovy.sql.Sql,我建议将其作为 bean 添加到 resources.groovy 文件中:

beans = {

    groovySql(groovy.sql.Sql, ref('dataSource'))

}

然后将它注入到任何你想使用它的地方:

class MyService {

    def groovySql
    ...

    def myMethod() {

        String query = "SELECT * FROM user WHERE ..."

        Map params = [param1: p1]

        List<GroovyRowResult> result = groovySql.rows(query, params)

        ...

    }

}

希望这可以帮助任何尝试执行普通 SQL 查询而无需将它们转换为 HQL 或标准的麻烦。