hibernate - 无法为 kotlin 和 JpaRepository 中的嵌套列表对象找到适当的构造函数错误
问题描述
当 JPA 尝试将查询的结果映射到结果存储库方法 DTO 时,我遇到以下错误:
org.hibernate.hql.internal.ast.QuerySyntaxException:
Unable to locate appropriate constructor on class [com.example.dto.User]. Expected arguments are: java.lang.String, java.lang.String, com.example.repository.DbRole
我在我的 Kotlin 项目中使用spring-boot-starter-data-jpa
和org.jetbrains.kotlin.plugin.jpa
插件。我有一个这样定义的存储库:
@Repository
internal interface JdbcUserRepository : UserRepository, JpaRepository<DbUser, String> {
override fun findUserByUsername(username: String): User?
}
请注意,JpaRepository (DbUser) 使用的类型与 findUserByUsername 方法 (User) 重新调整的类型不同,并且在上面的错误中,JPA 正确找到了 User 类 ( ...class [com.example.dto.User] ... ) 但角色没有。它期望目标 DTO 中有一个 DbRole,这是怎么回事。
DbUser 是一个@Entity 注释类,它引用另一个名为DbRole 的@Entity 注释类。两者定义如下:
@Entity
@Table(name = "user")
internal data class DbUser(
@Id @Column val username: String,
@Column val password: String,
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
name = "user_role",
joinColumns = [JoinColumn(name = "username", referencedColumnName = "username")],
inverseJoinColumns = [JoinColumn(name = "role_id", referencedColumnName = "id")]
) val roles: List<DbRole>
)
@Entity
@Table(name = "role")
internal data class DbRole(
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long,
@Column val roleName: String,
@Column val description: String
)
以下是 JPA 必须将结果映射到的类:
data class User(
val username: String,
val password: String,
val roles: List<Role>
)
data class Role(val roleName: String, val description: String)
有谁知道如何解决这个问题,JPA 正确地找到 DbRole 的嵌套实体列表并将其映射到 Role 的嵌套 DTO 列表?
解决方案
问题是数据库查询只能返回纯结果。持久性提供程序可以将其转换为具有嵌套实体列表的实体。至于dto
你必须自己解决问题。
因此,您可以使用User
带有构造函数的 dto 获得简单的结果,如下所示
public User(String username, String password, String roleName, String roleDescription) {
this.username = username;
this.password = password;
roles = new ArrayList<>();
roles.add(new Role(roleName, roleDescription));
}
然后你需要这样的存储库方法
@Query("select new com.example.dto.User(u.username, u.password, r.roleName, r.description) from DbUser u join u.roles r where u.username=:username")
List<User> findUserByUsername(@Param("username") String username);
在服务层处理结果
public Optional<User> findUserByUsername(username) {
List<User> users = findUserByUsername(username);
if(users.isEmpty()) {
return Optional.empty();
}
User user = users.get(0);
if(users.size() > 1) {
users.subList(1, users.size()).forEach(u -> user.getRoles().addAll(u.getRoles()));
}
return Optional.of(user);
}
您可以使用相同的方法Kotlin
推荐阅读
- reactjs - 如何在 React 中为每个屏幕尺寸设置尺寸?
- matlab - 使用 Matlab 基于密度函数生成具有不等步长的网格
- llvm - 在 LLVM 中创建一个包含指向自身的指针的结构
- linux - 签署虚拟盒模块(vboxdrv、vboxnetflt、vboxnetadp、vboxpci)Centos 8
- laravel - 导入CSV文件,删除空行并立即导出而不将其存储到数据库中 - laravel excel
- twitter-bootstrap - Bootstrap .container 和 .container-sm 之间的区别
- javascript - 我需要在 javascript / jQuery 中获取嵌套对象中的值列表
- android - 从android中的Html标签重定向到链接
- python - Python Tkinter - 形状调整
- ng-bootstrap - 如何使用 Ng-Bootstrap 6 在 Angular 9 中正确实现 Tooltip