Hibernate 命名查询 - 连接 3 个表
Posted
技术标签:
【中文标题】Hibernate 命名查询 - 连接 3 个表【英文标题】:Hibernate Named Query - join 3 tables 【发布时间】:2012-01-14 00:34:01 【问题描述】:我有 3 个 bean:组织、角色、用户
角色 - 组织关系 - @ManyToOne
角色 - 用户关系 - @ManyToMany
组织:
@Entity
@Table(name = "entity_organization")
public class Organization implements Serializable
private static final long serialVersionUID = -646783073824774092L;
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
Long id;
String name;
@OneToMany(targetEntity = Role.class, mappedBy = "organization")
List<Role> roleList;
...
角色:
@Entity
@Table(name = "entity_role")
public class Role implements Serializable
private static final long serialVersionUID = -8468851370626652688L;
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
Long id;
String name;
String description;
@ManyToOne
Organization organization;
...
用户:
@Entity
@Table(name = "entity_user")
public class User implements Serializable
private static final long serialVersionUID = -4353850485035153638L;
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
Long id;
@ManyToMany
@JoinTable(name = "entity_user_role",
joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"))
List<Role> roleList;
...
所以我需要获取指定用户的所有组织(首先我需要选择所有用户角色,然后选择所有具有此角色的组织)
我有一个实现此逻辑的 sql 语句(例如,我选择 id = 1 的用户):
SELECT * FROM entity_organization AS o
INNER JOIN entity_role r ON r.organization_id = o.id
INNER JOIN entity_user_role ur ON ur.role_id=r.id
WHERE ur.user_id = 1
如何使用休眠命名查询机制来实现这一点? 谢谢!
【问题讨论】:
【参考方案1】:@NamedQuery
>我在Organization
实体类上创建了以下@NamedQuery
。
@NamedQuery(name = "query", query = "SELECT DISTINCT o " +
"FROM Organization o, User u " +
"JOIN o.roles oRole " +
"JOIN u.roles uRole " +
"WHERE oRole.id = uRole.id AND u.id = :uId")
public class Organization ...
(我使用标准的 JPA 注释,但我的提供者是 Hibernate。)
测试
这是我运行的测试。
EntityManager em = ...
TypedQuery<Organization> q = em.createNamedQuery("query", Organization.class);
q.setParameter("uId", 1); // try it with 1L if Hibernate barks about it
for (Organization o : q.getResultList())
System.out.println(o.name);
使用下面的表格和示例数据,输出
A
B
请看看它是否适合你。
表格
CREATE TABLE `organization` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`description` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`organization_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
);
CREATE TABLE `user_has_role` (
`user_id` int(11) NOT NULL DEFAULT '0',
`role_id` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`user_id`,`role_id`)
);
ALTER TABLE `role` ADD CONSTRAINT `cst_organization_id`
FOREIGN KEY `fk_organiztaion_id` (`organization_id`)
REFERENCES `organization` (`id`);
(我用的和你的有点不同,但应该没太大关系。)
样本数据
`organization`
+----+------+
| id | name |
+----+------+
| 1 | A |
| 2 | B |
+----+------+
`role`
+----+------+-------------+-----------------+
| id | name | description | organization_id |
+----+------+-------------+-----------------+
| 1 | A | a | 1 |
| 2 | B | b | 1 |
| 3 | C | c | 2 |
+----+------+-------------+-----------------+
`user`
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
+----+
`user_has_role`
+---------+---------+
| user_id | role_id |
+---------+---------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
| 3 | 1 |
| 3 | 3 |
+---------+---------+
【讨论】:
它不起作用。 id = 2 的用户具有 id=1 的角色,因此他必须仅在组织 id = 1 中,但查询返回 2 行 @BraginiNI 我很草率,只检查了uId = 1
的查询结果。对于那个很抱歉。我已经更新了我的答案。对于 ID:1、2 和 3,它返回:A 和 B、B i> 和 A 和 B。如果没有 DISTINCT 关键字,则会返回重复的结果。
谁能澄清一下我们是如何从组织类中知道 o.roles 值的,因为它的属性仅为 roleList。【参考方案2】:
尝试如下 HQL:
select ur.roleList.organization from User ur where ur.id = 1
它会给你List<Organization>
。
【讨论】:
这是“ur.roleList.organization”部分中命名查询语法的错误,因为我认为它不是可用的语法。 “ur.roleList 很好用” 错误创建文件中定义的名称为“accountDaoImpl”的 bean 原因:org.hibernate.HibernateException:命名查询中的错误:Organization.findOrganizationsByUser以上是关于Hibernate 命名查询 - 连接 3 个表的主要内容,如果未能解决你的问题,请参考以下文章
如何强制 Hibernate 在组件上使用左外连接进行命名查询?