JPA Criteria API:关联实体路径导航与集合字段过滤教程

jpa criteria api:关联实体路径导航与集合字段过滤教程

本教程详细介绍了如何使用JPA Criteria API进行复杂查询,特别是涉及通过关联实体(如`@OneToOne`和`@OneToMany`)进行路径导航以及对集合内部字段进行过滤。文章通过具体的实体模型和代码示例,演示了如何正确构建`Join`和`Predicate`来查询符合特定条件的关联数据,避免了直接在集合路径上使用`equal`操作的常见错误。

1. JPA Criteria API 简介与关联查询挑战

JPA Criteria API 提供了一种类型安全且动态构建查询的方式,它允许开发者通过编程而非字符串拼接来定义查询条件,从而在编译时捕获潜在的错误。在处理复杂的数据模型时,特别是当实体之间存在一对一(@OneToOne)或一对多(@OneToMany)等关联关系,并且需要根据关联实体内部的属性进行过滤时,Criteria API 的路径导航能力显得尤为重要。

常见的挑战在于,当尝试过滤集合类型的关联属性时,直接对集合本身进行比较往往会导致错误。例如,如果一个Property实体包含一个List,我们不能直接比较propertyRoot.join(“amenities”).join(“interiors”).get(“name”)与一个字符串,因为interiors是一个集合,而get(“name”)试图从集合中获取一个名为”name”的属性,这在语义上是不正确的。正确的做法是深入到集合的元素层面,对集合中的每个元素进行条件判断。

2. 实体模型示例

为了更好地理解,我们使用以下实体模型作为示例:

// Property Entityclass Property {    // ... 其他属性    @OneToOne(mappedBy = "property", cascade = CascadeType.ALL)    @JsonManagedReference    private Amenities amenities;    // ... getter/setter}// Amenities Entityclass Amenities {    // ... 其他属性    @OneToMany(mappedBy = "amenities", cascade = CascadeType.ALL)    @JsonManagedReference    private List interiors;    // ... getter/setter}// Interiors Entitypublic class Interiors {    @Id    @GeneratedValue(strategy = GenerationType.AUTO)    private int id;    private String name; // 例如:"Gym", "Pool", "Sauna"    // ... getter/setter}

我们的目标是查询所有包含名为 “Gym” 的 Interiors 的 Property 实体。

集简云 集简云

软件集成平台,快速建立企业自动化与智能化

集简云 22 查看详情 集简云

3. 正确的Criteria API路径导航与集合过滤

要实现上述目标,我们需要通过 Join 操作逐步导航到 Interiors 实体,然后对 Interiors 实体中的 name 属性应用过滤条件。

3.1 核心思路

从 Property 实体开始,创建 Root。通过 propertyRoot.join(“amenities”) 导航到 Amenities 实体。再通过 amenitiesJoin.join(“interiors”) 导航到 Interiors 实体。请注意,这里 join(“interiors”) 返回的是 Join 类型,它代表了 interiors 集合中的每一个 Interiors 元素。在 Interiors 的 Join 对象上,使用 get(“name”) 获取 name 属性,并构建 equal 或 in 等谓词。

3.2 示例代码:查询包含特定名称内饰的物业

以下代码演示了如何查询所有拥有名为 “Gym” 的内饰的 Property 实体:

import javax.persistence.EntityManager;import javax.persistence.PersistenceContext;import javax.persistence.criteria.CriteriaBuilder;import javax.persistence.criteria.CriteriaQuery;import javax.persistence.criteria.Join;import javax.persistence.criteria.Root;import javax.persistence.criteria.Predicate;import java.util.List;// 假设在一个Spring Data JPA Repository或Service中public class PropertyService {    @PersistenceContext    private EntityManager entityManager;    public List findPropertiesWithInteriorName(String interiorName) {        CriteriaBuilder cb = entityManager.getCriteriaBuilder();        CriteriaQuery cq = cb.createQuery(Property.class);        Root propertyRoot = cq.from(Property.class);        // 1. 导航到 Amenities (OneToOne 关联)        // Join        Join amenitiesJoin = propertyRoot.join("amenities");        // 2. 导航到 Interiors (OneToMany 关联)        // 此时 interiorsJoin 代表了 Amenities 实体中 List 集合里的每一个 Interiors 元素        Join interiorsJoin = amenitiesJoin.join("interiors");        // 3. 构建谓词:interiorsJoin 的 name 属性等于指定名称        Predicate namePredicate = cb.equal(interiorsJoin.get("name"), interiorName);        // 4. 将谓词应用到查询的 where 子句        cq.where(namePredicate);        // 5. 执行查询并返回结果        return entityManager.createQuery(cq).getResultList();    }    // 调用示例    public static void main(String[] args) {        // 假设已经获取到 EntityManager 实例        // PropertyService service = new PropertyService();        // List gymProperties = service.findPropertiesWithInteriorName("Gym");        // gymProperties.forEach(p -> System.out.println("Property ID: " + p.getId()));    }}

3.3 使用 IN 谓词过滤集合

如果需要查询内饰名称在给定列表中的所有物业,可以使用 in 谓词。这在需要匹配多个值时非常有用,例如查找内饰名称为 “Gym” 或 “Pool” 的物业。

import java.util.Arrays;import java.util.List;public class PropertyService {    // ... (同上,省略EntityManager注入和findPropertiesWithInteriorName方法)    public List findPropertiesWithInteriorNamesInList(List interiorNames) {        CriteriaBuilder cb = entityManager.getCriteriaBuilder();        CriteriaQuery cq = cb.createQuery(Property.class);        Root propertyRoot = cq.from(Property.class);        Join amenitiesJoin = propertyRoot.join("amenities");        Join interiorsJoin = amenitiesJoin.join("interiors");        // 构建 IN 谓词:interiorsJoin 的 name 属性在 interiorNames 列表中        Predicate inPredicate = interiorsJoin.get("name").in(interiorNames);        cq.where(inPredicate);        return entityManager.createQuery(cq).getResultList();    }    // 调用示例    public static void main(String[] args) {        // ...        // List desiredInteriors = Arrays.asList("Gym", "Pool");        // List gymOrPoolProperties = service.findPropertiesWithInteriorNamesInList(desiredInteriors);        // gymOrPoolProperties.forEach(p -> System.out.println("Property ID: " + p.getId()));    }}

4. 注意事项与最佳实践

理解 Join 的作用: join() 方法在 Criteria API 中不仅用于连接关联实体,更重要的是它返回一个 Join 对象,这个对象代表了被连接的实体本身。对 Join 对象调用 get() 方法,可以访问该被连接实体的属性。OneToMany 关联的 Join: 当对 OneToMany 关联进行 join() 操作时,JPA 会在内部处理集合的遍历。生成的 SQL 通常会包含一个 INNER JOIN(默认)或 LEFT JOIN(如果指定 JoinType.LEFT),将主实体与集合中的每个元素连接起来。这意味着如果一个 Property 有多个 Interiors 满足条件,那么该 Property 可能会在结果集中出现多次(尽管 CriteriaQuery 会自动去重,但底层查询可能会返回重复行)。JoinType 的选择: 默认情况下,join() 使用 INNER JOIN。如果希望即使关联实体不存在也返回主实体(例如,即使没有 Amenities 或 Interiors 也返回 Property),则应明确指定 JoinType.LEFT:

Join amenitiesJoin = propertyRoot.join("amenities", JoinType.LEFT);Join interiorsJoin = amenitiesJoin.join("interiors", JoinType.LEFT);

性能考量: 复杂的 Join 操作可能会影响查询性能。确保数据库索引在关联字段和过滤字段上都已正确建立。对于非常大的集合,考虑是否可以通过其他方式优化查询逻辑。去重问题: 如果你查询的是 Property 实体,并且一个 Property 有多个 Interiors 都满足条件,那么在底层 SQL 中,这个 Property 可能会被连接多次。CriteriaQuery 通常会自动处理结果的去重,但如果你在 select 子句中选择了其他字段或自定义了结果类型,可能需要手动添加 cq.distinct(true) 来确保结果集的唯一性。

总结

通过 JPA Criteria API 进行关联实体路径导航和集合字段过滤是构建复杂查询的强大工具。关键在于正确地使用 join() 方法深入到关联实体的层次,并在正确的 Join 对象上应用谓词。理解 Join 的语义以及 OneToMany 关联在查询中的行为,能够帮助开发者编写出高效且正确的查询语句,从而避免常见的错误并充分利用 JPA 的强大功能。

以上就是JPA Criteria API:关联实体路径导航与集合字段过滤教程的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/286526.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
多名玩家涉嫌世嘉以及SE游戏代理氪金诈骗被捕
上一篇 2025年11月4日 18:41:56
ASP网站301跳转代码实现
下一篇 2025年11月4日 18:42:02

相关推荐

  • mysql临时表如何使用_PHP中操作mysql临时表的具体步骤

    MySQL临时表仅在当前会话可见,连接关闭后自动删除,适合中间数据处理。使用PHP操作时,先通过mysqli或PDO建立数据库连接,再执行CREATE TEMPORARY TABLE语句创建临时表,随后可像普通表一样进行INSERT、SELECT及JOIN等操作。临时表可与永久表同名且优先被使用,支…

    2026年9月24日
    000
  • UC浏览器怎么查看和清除LocalStorage数据 UC浏览器LocalStorage数据管理方法

    可通过隐私设置清除或开发者工具查看LocalStorage。①在UC浏览器设置中选择“隐私与安全”→“清除浏览数据”,勾选“Cookie及其他网站数据”即可批量删除LocalStorage;②打开uc://inspect启用开发者工具,通过电脑Chrome远程调试查看具体键值对;③root设备后使用…

    2026年9月24日
    200
  • Java语法基础中static关键字可以修饰哪些内容

    static关键字用于定义类成员,包括静态变量(如计数器)、静态方法(如工具方法)、静态代码块(类加载时执行)和静态内部类(不依赖外部类实例),均属于类而非对象,通过类名访问,提升成员至类级别实现共享与提前使用。 static 关键字在 Java 中主要用于定义与类相关而非与对象实例相关的成员。它不…

    2026年9月24日
    100
  • 抖音怎么看注册时间?怎么看百度网盘注册时间

    抖音已然成为国内炙手可热的短视频平台之一。凭借其独特的智能推荐系统,用户能够在短时间内找到自己喜爱的内容。你是否知道,你的抖音注册时间实际上隐含了许多关于你的社交轨迹的信息呢?本文将带领大家一同揭秘抖音注册时间背后的故事。 一、抖音注册时间的意义 1. 用户活跃程度的体现 抖音注册时间能够帮助我们判…

    2026年9月24日
    100
  • mysql中*是什么意思 mysql星号通配符解析

    在 mysql 中,星号()最常用于 select 语句中代表所有列,但应谨慎使用。1)它方便查看所有数据,但可能返回不必要的数据,影响性能。2)使用可能降低代码可维护性,建议明确列出所需列。3)在like操作符中,不是通配符,需用regexp。4)在视图中使用可能导致定义失效。5)可结合limit…

    2026年9月24日
    000
  • 为什么要4k对齐

    早期硬盘的每个扇区以512字节为标准,而新一代硬盘的扇区容量则为4096个字节,即所谓的4k扇区。虽然硬盘标准已经更新,但操作系统仍然使用512字节扇区的标准。为了确保兼容性,硬盘制造商将4k扇区模拟成了512字节扇区。文件系统的块(簇)通常是512字节的倍数,而新系统大多设定为4k的倍数,例如li…

    2026年9月24日
    000
  • 抖音怎么下载视频?抖音怎么提取别人的视频

    抖音作为一个热门的短视频社交平台,凭借其多样化的短视频内容吸引了众多用户。部分用户在浏览抖音视频时,希望能将其保存下来以供后续观看。那么,如何在抖音上下载视频呢?接下来,本文将详细介绍几种下载抖音视频的方法以及相关的注意事项。 一、抖音视频下载方法 使用抖音官方提供的下载功能 抖音自身具备下载功能,…

    2026年9月24日
    400
  • google浏览器怎么把网页保存为PDF_google浏览器网页保存为PDF方法

    使用Chrome将网页保存为PDF,首先按Ctrl+P进入打印界面,选择“另存为PDF”并调整设置后保存;也可通过F12打开开发者工具,截取指定元素或完整页面截图后转为PDF;还可安装“Save as PDF”等扩展程序实现更高质量的导出。 如果您希望将当前浏览的网页完整保存以便离线查看或分享,Go…

    2026年9月24日
    000
  • windows怎么关闭cortana进程_彻底关闭小娜(cortana)后台进程的方法

    1、可通过任务管理器结束Cortana进程并禁用其启动项;2、修改注册表或组策略可永久关闭;3、重命名系统目录文件夹可阻止其运行。 如果您发现Windows系统中Cortana(小娜)后台进程占用资源或影响系统性能,可能是该服务在后台持续运行。以下是彻底关闭Cortana进程的操作步骤: 本文运行环…

    2026年9月24日
    800
  • 苹果过时产品名单更新,M5 iPad Pro 开箱视频流出

    苹果过时产品名单更新,M5 iPad Pro 开箱视频流出苹果过时产品名单更新,M5 iPad Pro 开箱视频流出苹果过时产品名单更新,M5 iPad Pro 开箱视频流出苹果过时产品名单更新,M5 iPad Pro 开箱视频流出

    日前,苹果已将 iphone 11 pro max 和 apple watch series 3 的所有型号列入“过时产品”(vintage product)行列。 根据苹果的规定,一款产品在停止销售满 5 年后,可能会被归为“过时产品”。不过,这一分类并不会显著影响售后服务——苹果仍会继续为这些设…

    2026年9月24日 用户投稿
    600
  • VSCode如何实现AI版本迁移辅助 VSCode跨版本升级的智能建议

    vscode的“ai版本迁移辅助”并非独立功能,而是通过扩展兼容性检查、设置同步、lsp/dap协议支持及社区资源等生态能力协同实现;2. 升级后扩展无法工作时,应检查更新日志、尝试降级或重新安装扩展、禁用冲突扩展、查看控制台错误信息并向作者报告问题;3. 备份设置和扩展列表可通过启用设置同步、手动…

    2026年9月24日
    1000
  • Java语法基础中如何导入其他包中的类

    使用import关键字可导入其他包中的类,如import java.util.ArrayList;2. 通过import java.util.*可导入整个包;3. 不导入时可用全限定名访问类,但不推荐;4. 类名冲突时需使用全限定名区分,如java.sql.Date。 在Java中使用其他包中的类,…

    2026年9月24日
    1100
  • 抖音怎么投屏到电视上?抖音如何TV投屏

    智能电视已经成为了家庭娱乐的核心设备。在享受高清晰度大屏幕带来的视觉震撼的同时,抖音这款广受欢迎的短视频应用也吸引了众多用户。如何将抖音中的精彩内容传输到电视屏幕上,与家人和朋友一同分享呢?本文将详细介绍几种简单有效的方法,帮助您轻松实现抖音投屏到电视。 一、方法一:利用电视内置投屏功能 1. 内置…

    2026年9月24日
    000
  • uc浏览器如何清除指定的网站数据_UC浏览器定点清除网站Cookie与缓存

    可针对特定网站清理缓存或Cookie解决UC浏览器访问异常。1、进入设置→隐私与安全→管理网站数据,搜索目标网站并清除其数据;2、使用无痕浏览模式访问网站,避免数据残留;3、通过文件管理器手动删除UC浏览器缓存目录下对应域名的缓存文件夹。 如果您在使用UC浏览器访问某些网站时遇到加载异常、登录状态失…

    2026年9月24日
    000
  • MAC系统怎么开启防火墙_MAC开启防火墙教程

    1、建议在Mac系统中开启防火墙以提升网络安全,可通过“系统设置”中的“网络-防火墙”选项启用;2、高级用户可使用终端命令sudo /usr/libexec/ApplicationFirewall/socketfilterfw –setglobalstate on开启服务;3、启用后可在…

    2026年9月24日
    100
  • APM开发阅读

    APM开发阅读APM开发阅读APM开发阅读APM开发阅读

    我阅读apm的源码有两个主要目的:一是学习,了解飞控系统和大型项目的组织结构;二是为了移植的需要,满足项目需求。近年来,少儿编程市场非常火热,许多厂商推出了相关的产品,但这些产品大多使用空心杯电机,导致动力不足,且扩展性有限。许多任务需要io或图像识别的支持。 因此,我在考虑使用APM裁剪版的飞控系…

    2026年9月24日 用户投稿
    1600
  • MySQL中SQL注入防范 SQL注入攻击的预防与应对措施

    sql注入的防范核心在于参数化查询。具体措施包括:1.始终使用参数化查询,将用户输入视为数据而非可执行代码;2.对输入进行过滤与校验,如验证格式、转义特殊字符;3.遵循最小权限原则,限制数据库账号权限;4.控制错误信息输出,避免暴露敏感细节;5.定期更新框架与插件,及时修补漏洞。这些方法结合使用能有…

    2026年9月24日
    000
  • 如何在Linux中切换用户身份?

    Linux中切换用户主要用su和sudo命令;2. su切换用户需密码,su -可加载完整环境;3. sudo允许授权用户以root等身份执行命令而无需对方密码;4. 推荐使用sudo -i或sudo su -切换到root;5. 普通用户需加入sudo组或配置/etc/sudoers文件;6. 编…

    2026年9月24日
    100
  • 如何在mysql中升级高可用集群

    先确认版本兼容性、应用依赖及备份完整性,再按架构选择升级路径。对Group Replication或InnoDB Cluster采用滚动升级,先升从节点最后升主节点;MHA/Orchestrator架构先升备库再切换主库;PXC需停集群全量升级。替换二进制后启动实例并运行mysql_upgrade,…

    2026年9月24日
    000
  • VSCode的扩展设置是全局的还是局部的?

    VSCode扩展设置默认全局生效,存储于用户配置文件中,但部分扩展如ESLint、Prettier和Python支持项目级局部配置,通过在项目根目录的.vscode/settings.json文件中定义,可覆盖全局设置;在设置界面中,齿轮图标表示可被工作区覆盖,锁图标表示仅限全局修改,用户可根据需求…

    2026年9月24日
    200

发表回复

登录后才能评论
关注微信