java - 从表和连接表中选择部分列 Criteria API
问题描述
我正在尝试从不同的表中选择 2 列(它们已连接),但我无法使用 Criteria API 使其工作。问题是,我创建了一个 DTO 类作为 Projection,但我无法将连接的表实体转换为内部类。为了澄清,这是我的课程:
用户:
@Entity
@Table(name = "users", indexes = {@Index(columnList = "email", unique = true)})
public class User extends BaseEntity {
@Column(nullable = false)
private String firstName;
@ManyToMany
@JoinTable(name = "user_roles",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<Role> roles;
角色:
@Table(name = "roles")
@Entity
public class Role extends BaseEntity {
@Column(nullable = false)
private String name;
@Column(nullable = false)
private String description;
DTO 类:
public class UserRoleDto {
private String email;
private Set<RoleDto> roles;
public UserRoleDto(String email, Set<RoleDto> roles) {
this.email = email;
this.roles = roles;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Set<RoleDto> getRoles() {
return roles;
}
public void setRoles(Set<RoleDto> roles) {
this.roles = roles;
}
public static class RoleDto {
private String name;
public RoleDto(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
最后,我尝试过的:
@Override
public Optional<UserRoleDto> findByIdWithRoles(UUID id) {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<UserRoleDto> query = builder.createQuery(UserRoleDto.class);
Root<User> root = query.from(User.class);
root.fetch("roles", JoinType.LEFT);
query.where(builder.equal(root.get("id"), id));
query.select(builder.construct(UserRoleDto.class, root.get("email"), root.join("roles")));
UserRoleDto user = entityManager.createQuery(query).getSingleResult();
return Optional.ofNullable(user);
}
如您所见,我只想查询 user.firstName 并从 Role 连接表中查询名称。如何在这里从 Role 转换为 UserRoleDto.RoleDto?
谢谢!
解决方案
这行不通。您只能使用 JPA 构造函数语法从标量结果创建对象,但不能用于嵌套结构。您必须自己构建对象图。
无论如何,这是Blaze-Persistence Entity Views的完美用例。
Blaze-Persitence 是一个基于 JPA 的查询构建器,它支持 JPA 模型之上的许多高级 DBMS 功能。我在它之上创建了实体视图,以允许在 JPA 模型和自定义接口定义模型之间轻松映射,例如 Spring Data Projections on steroids。这个想法是您以您喜欢的方式定义目标结构,并通过 JPQL 表达式将属性(getter)映射到实体模型。由于属性名称用作默认映射,因此您通常不需要显式映射,因为 80% 的用例是拥有作为实体模型子集的 DTO。
您的模型的映射可能看起来很简单,如下所示
@EntityView(User.class)
interface UserRoleDto {
String getEmail();
Set<RoleDto> getRoles();
}
@EntityView(Role.class)
interface RoleDto {
String getName();
}
查询是将实体视图应用于查询的问题,最简单的就是通过 id 进行查询。
UserRoleDto dto = entityViewManager.find(entityManager, UserRoleDto.class, id);
但是 Spring Data 集成允许您几乎像 Spring Data Projections 一样使用它:https ://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
它只会获取您告诉它获取的映射
推荐阅读
- xml - notepad++ xml 验证返回显示“缺少架构或无效命名空间”
- javascript - Nuxt.js 嵌入代码呈现 iframe 但不呈现脚本
- linux - 如何在ansible中重命名文件
- spring-boot - 带有 CompletableFuture 的 Spring-boot AOP 建议
- javascript - 这个 express 变量在做什么?
- php - PHP imagick - 将 eps 转换为 jpg 但质量很差
- python - 从 Python 外部运行 Python 脚本错误:导入 etree 时 DLL 加载失败:找不到指定的模块
- kubernetes - 无法在 Kubernetes 集群上部署简单的“Hello World”应用程序
- amazon-web-services - 如何更改 AWS 安全组的出口规则?
- python - EC2服务器中的Python Geoip2 maxminddb.reader错误