如何使用JPA Criteria API实现@MapsId一对一左连接
JPA Criteria 左连接共享主键一对一关联实现
核心问题原因
当前实体配置为单向@OneToOne关联:关联关系仅定义在PostDetails类的post属性上,Post类中没有定义对应PostDetails类型的关联属性,因此无法直接填写join方法的属性名参数。
实现方案
方案1:补全双向关联(生产环境推荐)
这是JPA标准规范推荐的写法,维护成本最低,不需要手动写关联条件。
- 首先在
Post实体类中补充反向关联配置:
@Entity(name = "Post") @Table(name = "post") public class Post { @Id @GeneratedValue private Long id; private String title; // 新增反向一对一关联,mappedBy指向PostDetails类中关联Post的属性名"post" @OneToOne(mappedBy = "post", fetch = FetchType.LAZY) private PostDetails postDetails; //Getters and setters omitted for brevity }
- 补完关联后编写Criteria查询,
join方法第一个参数直接填Post类中新增的PostDetails属性名即可,JPA会自动根据注解配置生成关联条件,不需要手动调用on()方法写关联逻辑:
CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery<CustomClass> query = cb.createQuery(CustomClass.class); Root<Post> postRoot = query.from(Post.class); // 左连接参数直接填Post实体中的postDetails属性名 Join<Post, PostDetails> joinPostDetails = postRoot.join("postDetails", JoinType.LEFT); // 封装CustomClass返回结果,根据你自己的CustomClass构造函数调整参数顺序即可 query.select(cb.construct( CustomClass.class, postRoot.get("id"), postRoot.get("title"), joinPostDetails.get("createdOn"), joinPostDetails.get("createdBy") ));
方案2:不修改实体,保留单向关联
如果不想调整现有实体结构,可以直接创建两个查询根节点,手动拼接左连接条件,不需要调用Root.join()方法:
CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery<CustomClass> query = cb.createQuery(CustomClass.class); Root<Post> postRoot = query.from(Post.class); // 直接创建PostDetails的查询根 Root<PostDetails> detailsRoot = query.from(PostDetails.class); // 手动指定左连接条件:匹配Post的id和PostDetails关联的Post,同时保留PostDetails不存在的空记录 query.where(cb.or( cb.equal(postRoot.get("id"), detailsRoot.get("post")), cb.isNull(detailsRoot.get("id")) )); // 封装CustomClass返回结果 query.select(cb.construct( CustomClass.class, postRoot.get("id"), postRoot.get("title"), detailsRoot.get("createdOn"), detailsRoot.get("createdBy") ));
📌 注意事项:
- 写JPA查询的属性路径时,永远使用实体类中的属性名,不要直接写数据库表的字段名。比如不要写
detailsRoot.get("post_id"),PostDetails中关联Post的属性名是post,直接传"post"即可,JPA会根据@JoinColumn(name = "post_id")的配置自动映射到数据库字段。- 如果已经在实体类上配置了完整的JPA关联映射,不需要手动调用
join.on()写关联条件,JPA会自动生成正确的关联SQL,手动重复写条件反而可能导致查询结果不符合预期。
内容的提问来源于stack exchange,提问作者Masudul
相关产品推荐
相关产品推荐

