使用 JPA Criteria 查询获取 ManyToOne 关联数据

使用 JPA Criteria 查询获取 ManyToOne 关联数据

本文旨在解决在使用 JPA Criteria 查询时,如何正确获取 `ManyToOne` 关联实体中的数据。通过 `Join` 操作,我们可以访问关联实体中的属性,并将其应用于查询条件中,避免常见的 “Unable to locate Attribute” 错误。同时,建议使用元模型(Metamodel)进行类型安全的查询。

在使用 hibernate JPA 进行数据查询时,经常会遇到需要访问关联实体属性的场景,特别是当实体之间存在 ManyToOne 关系时。直接在 Criteria 查询中使用关联实体的属性,会导致 Unable to locate Attribute 错误。本文将详细介绍如何通过 Join 操作正确地访问 ManyToOne 关联实体中的数据,并提供示例代码和注意事项。

问题分析

假设我们有两个实体 GroupEntity 和 UserEntity,其中 GroupEntity 通过 ManyToOne 关系关联到 UserEntity。GroupEntity 包含 name 和 status 属性,而 UserEntity 包含 userCode 属性。如果我们需要查询 userCode 匹配特定值,或者 name 匹配其他特定值的 GroupEntity 列表,直接在 GroupEntity 的 Root 上使用 userCode 属性会抛出异常,因为 userCode 实际上是 UserEntity 的属性。

解决方案:使用 Join 操作

要解决这个问题,我们需要使用 Join 操作将 GroupEntity 和 UserEntity 连接起来。通过 Join 操作,我们可以获得 UserEntity 的引用,从而访问其属性。

以下是修改后的 JPA Criteria 查询代码示例:

public List<GroupEntity> getData(final String userCode,                                    final String currentGroupName, final String newGroupName) {      final EntityManager entityManager = entityManagerProvider.get();     final CriteriaBuilder cb = entityManager.getCriteriaBuilder();     final CriteriaQuery<GroupEntity> cq = cb.createQuery(GroupEntity.class);     final Root<GroupEntity> root = cq.from(GroupEntity.class);      // 使用 Join 操作连接 GroupEntity 和 UserEntity     Join<GroupEntity, UserEntity> user = root.join("userEntity");      cq.select(root).where(cb.or(             cb.equal(user.get("userCode"), userCode), // 使用 user.get("userCode") 访问 UserEntity 的 userCode 属性             cb.equal(root.get("name"), currentGroupName),             cb.equal(root.get("name"), newGroupName)));      return entityManager.createQuery(cq).getResultList(); }

代码解释:

  1. Join<GroupEntity, UserEntity> user = root.join(“userEntity”);:这行代码创建了一个 Join 对象,将 GroupEntity 的 root 和 UserEntity 连接起来。”userEntity” 是 GroupEntity 中 @ManyToOne 注解指定的属性名称。
  2. cb.equal(user.get(“userCode”), userCode):使用 user.get(“userCode”) 可以访问 UserEntity 的 userCode 属性,并将其用于查询条件。

示例实体类

为了更好地理解上述代码,以下是 GroupEntity 和 UserEntity 的示例代码:

使用 JPA Criteria 查询获取 ManyToOne 关联数据

蓝心千询

蓝心千询是vivo推出的一个多功能ai智能助手

使用 JPA Criteria 查询获取 ManyToOne 关联数据34

查看详情 使用 JPA Criteria 查询获取 ManyToOne 关联数据

@Entity @Table(name = "groups") public class GroupEntity extends BaseEntity {      @Id     @SequenceGenerator(name = "beta_group_seq", sequenceName = "group_seq", allocationSize = 1)     @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "group_seq")     @Column(name = "id")     private Long id;      @Column(name = "name", length = 1400)     private String name;      @ManyToOne(fetch = FetchType.LAZY)     @JoinColumn(name = "user_id")     private UserEntity userEntity;      @Column(name = "status")     private String status;      // Getters and setters }  @Entity @Table(name = "users") public class UserEntity extends BaseEntity {      @Id     @GeneratedValue(strategy = GenerationType.IDENTITY)     @Column(name = "id")     private Long id;      @Column(name = "user_code", nullable = false, unique = true)     private String userCode;      // Getters and setters }  @Getter @MappedSuperclass public abstract class BaseEntity {      @Column(name = "CREATED_BY", length = 8, updatable = false)     private String createdBy;      @Temporal(TemporalType.TIMESTAMP)     @Column(name = "CREATION_DATE", updatable = false)     private Date creationDate;      @Column(name = "LAST_UPDATED_BY", length = 8, updatable = false)     private String lastUpdatedBy;      @Temporal(TemporalType.TIMESTAMP)     @Column(name = "LAST_UPDATED_DATE", updatable = false)     private Date lastUpdatedDate; }

使用元模型(Metamodel)进行类型安全查询

虽然使用字符串指定属性名称可以解决问题,但存在类型安全问题。如果属性名称发生变化,编译器无法检测到错误。为了解决这个问题,可以使用元模型(Metamodel)进行类型安全的查询。

首先,需要配置 maven 插件来生成元模型类。在 pom.xml 文件中添加以下插件:

<plugin>     <groupId>org.hibernate.orm.tooling</groupId>     <artifactId>hibernate-jpamodelgen</artifactId>     <version>${hibernate.version}</version>     <executions>         <execution>             <goals>                 <goal>generate</goal>             </goals>         </execution>     </executions>     <configuration>         <outputDirectory>src/main/Java</outputDirectory>     </configuration> </plugin>

然后,重新编译项目,Hibernate 将会自动生成元模型类,例如 GroupEntity_ 和 UserEntity_。

修改后的 JPA Criteria 查询代码如下:

public List<GroupEntity> getData(final String userCode,                                    final String currentGroupName, final String newGroupName) {      final EntityManager entityManager = entityManagerProvider.get();     final CriteriaBuilder cb = entityManager.getCriteriaBuilder();     final CriteriaQuery<GroupEntity> cq = cb.createQuery(GroupEntity.class);     final Root<GroupEntity> root = cq.from(GroupEntity.class);      // 使用 Join 操作连接 GroupEntity 和 UserEntity     Join<GroupEntity, UserEntity> user = root.join(GroupEntity_.userEntity);      cq.select(root).where(cb.or(             cb.equal(user.get(UserEntity_.userCode), userCode), // 使用 UserEntity_.userCode 访问 UserEntity 的 userCode 属性             cb.equal(root.get(GroupEntity_.name), currentGroupName),             cb.equal(root.get(GroupEntity_.name), newGroupName)));      return entityManager.createQuery(cq).getResultList(); }

代码解释:

  1. Join<GroupEntity, UserEntity> user = root.join(GroupEntity_.userEntity);:使用 GroupEntity_.userEntity 代替字符串 “userEntity”,可以获得类型安全的 Join 对象。
  2. cb.equal(user.get(UserEntity_.userCode), userCode):使用 UserEntity_.userCode 代替字符串 “userCode”,可以访问 UserEntity 的 userCode 属性,并进行类型安全的比较。

注意事项

  • 确保 @ManyToOne 注解中的 fetch 属性设置为 FetchType.LAZY,以避免不必要的性能开销。
  • 在使用 Join 操作时,确保连接的属性名称与实体类中的属性名称一致。
  • 推荐使用元模型(Metamodel)进行类型安全的查询,以提高代码的可维护性和可靠性。

总结

通过本文,我们学习了如何使用 JPA Criteria 查询获取 ManyToOne 关联实体中的数据。通过 Join 操作,我们可以访问关联实体中的属性,并将其应用于查询条件中。同时,建议使用元模型(Metamodel)进行类型安全的查询。掌握这些技巧可以帮助我们编写更高效、更可靠的 JPA 查询代码。

暂无评论

发送评论 编辑评论


				
上一篇
下一篇
text=ZqhQzanResources