
本文详细介绍了在jpa和hibernate环境中,如何根据关联表(外键关联实体)的属性值来筛选主实体数据。我们将探讨三种主要的实现方式:简洁直观的jpa jpql、类型安全且灵活的jpa criteria api,以及针对hibernate用户的传统criteria api。通过具体代码示例,本教程旨在帮助开发者理解并掌握在复杂数据关联场景下构建精确查询的技术。
在企业级应用开发中,数据模型通常包含多个相互关联的实体。当需要根据一个实体(主实体)的关联实体(外键关联)的特定属性值来检索主实体数据时,就需要构建跨越这些关联的查询。例如,从一个队列(Queue)实体中,筛选出属于特定地点(Location)和特定队列房间(QueueRoom)的所有队列。本教程将以一个Queue实体为例,演示如何高效地实现这类复合筛选。
假设我们有一个Queue实体,它与Location和QueueRoom实体存在多对一的关联关系:
import javax.persistence.*;
@Entity
@Table(name = "queue")
public class Queue {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "queue_id")
private Integer queueId;
@ManyToOne
@JoinColumn(name = "location_id", nullable = false)
private Location location; // 关联Location实体
@ManyToOne
@JoinColumn(name = "queue_room_id", nullable = true)
public QueueRoom queueRoom; // 关联QueueRoom实体
// Getters and Setters...
public Integer getQueueId() { return queueId; }
public void setQueueId(Integer queueId) { this.queueId = queueId; }
public Location getLocation() { return location; }
public void setLocation(Location location) { this.location = location; }
public QueueRoom getQueueRoom() { return queueRoom; }
public void setQueueRoom(QueueRoom queueRoom) { this.queueRoom = queueRoom; }
}
// Location 和 QueueRoom 实体结构类似,包含一个 String uuid 字段
@Entity
@Table(name = "location")
class Location {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String uuid;
// Getters and Setters...
public String getUuid() { return uuid; }
public void setUuid(String uuid) { this.uuid = uuid; }
}
@Entity
@Table(name = "queue_room")
class QueueRoom {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String uuid;
// Getters and Setters...
public String getUuid() { return uuid; }
public void setUuid(String uuid) { this.uuid = uuid; }
}我们的目标是根据location的uuid和queueRoom的uuid来查询Queue列表。
JPQL 是一种面向对象的查询语言,它在实体和它们的属性上操作,而不是直接在数据库表和列上操作。对于关联实体的属性筛选,JPQL 提供了一种非常直观和简洁的方式。
要实现基于关联表值的筛选,可以直接通过点号 (.) 访问关联实体的属性。多个条件可以使用 AND 逻辑运算符连接。
SELECT q FROM Queue q WHERE q.location.uuid = :locationUuid AND q.queueRoom.uuid = :queueRoomUuid
在上述JPQL查询中:
通常通过 EntityManager 来创建和执行 JPQL 查询。
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import java.util.List;
public class QueueRepository {
private EntityManager entityManager; // 注入或获取EntityManager实例
public QueueRepository(EntityManager entityManager) {
this.entityManager = entityManager;
}
public List<Queue> getAllQueuesByLocationAndQueueRoom(String locationUuid, String queueRoomUuid) {
String jpql = "SELECT q FROM Queue q " +
"WHERE q.location.uuid = :locationUuid " +
"AND q.queueRoom.uuid = :queueRoomUuid";
TypedQuery<Queue> query = entityManager.createQuery(jpql, Queue.class);
query.setParameter("locationUuid", locationUuid);
query.setParameter("queueRoomUuid", queueRoomUuid);
return query.getResultList();
}
}优点:
缺点:
JPA Criteria API 是一种类型安全的、程序化的查询构建方式。它允许开发者通过 Java 代码构建查询,从而在编译时捕获潜在的错误,并方便地构建动态查询。
import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Predicate;
import java.util.List;
public class QueueRepository {
private EntityManager entityManager;
public QueueRepository(EntityManager entityManager) {
this.entityManager = entityManager;
}
public List<Queue> getAllQueuesByLocationAndQueueRoomCriteria(String locationUuid, String queueRoomUuid) {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Queue> criteria = builder.createQuery(Queue.class);
Root<Queue> queueRoot = criteria.from(Queue.class); // 定义查询的根实体
// 构建第一个条件:q.location.uuid = :locationUuid
Predicate locationPredicate = builder.equal(
queueRoot.get("location").get("uuid"), // 导航到 location 实体,再获取 uuid 属性
locationUuid
);
// 构建第二个条件:q.queueRoom.uuid = :queueRoomUuid
Predicate queueRoomPredicate = builder.equal(
queueRoot.get("queueRoom").get("uuid"), // 导航到 queueRoom 实体,再获取 uuid 属性
queueRoomUuid
);
// 使用 builder.and() 将两个条件组合起来
criteria.where(builder.and(locationPredicate, queueRoomPredicate));
return entityManager.createQuery(criteria).getResultList();
}
}代码解析:
优点:
缺点:
虽然 JPA Criteria API 是推荐的标准化方式,但对于仍在使用旧版 Hibernate 或熟悉其原生 Criteria API 的开发者,了解其实现方式也很有价值。需要注意的是,Hibernate 原生 Criteria API 在 Hibernate 5.2 之后已被标记为废弃(Deprecated),并建议使用 JPA Criteria API。
原始问题中尝试的方法非常接近,但关键在于如何正确地将条件应用到根查询,并正确地执行查询。
import org.hibernate.Session;
import org.hibernate.Criteria;
import org.hibernate.criterion.Restrictions;
import org.hibernate.sql.JoinType; // 用于指定连接类型
import java.util.List;
public class QueueRepository {
private Session currentSession; // 注入或获取Hibernate Session实例
public QueueRepository(Session currentSession) {
this.currentSession = currentSession;
}
@SuppressWarnings("unchecked")
public List<Queue> getAllQueuesByLocationAndQueueRoomHibernateCriteria(String locationUuid, String queueRoomUuid) {
Criteria criteria = currentSession.createCriteria(Queue.class, "q");
// 创建别名并添加限制到根Criteria
// 使用 createAlias 而不是 createCriteria 来避免创建子 Criteria 并确保所有限制都在根级别
criteria.createAlias("q.location", "ql", JoinType.INNER_JOIN);
criteria.createAlias("q.queueRoom", "qr", JoinType.INNER_JOIN);
// 添加条件到根Criteria
criteria.add(Restrictions.eq("ql.uuid", locationUuid));
criteria.add(Restrictions.eq("qr.uuid", queueRoomUuid));
// 假设有一个 includeVoidedObjects 方法,这里也加入
// includeVoidedObjects(criteria, false); // 根据实际情况决定是否需要
return criteria.list();
}
}代码解析:
注意事项:
在JPA/Hibernate中,根据关联表值进行筛选是常见的需求。无论是通过JPQL的简洁语法,还是JPA Criteria API的类型安全和动态构建能力,都能够有效地实现这一目标。
最佳实践:
通过掌握这些查询技术,开发者可以更灵活、高效地处理复杂的数据检索场景,构建健壮且高性能的持久层。
以上就是基于JPA/Hibernate通过关联表值进行数据筛选的教程的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号