无法在Kotlin和JpaRepository中为嵌套列表对象找到适当的构造函数错误 [英] Unable to locate appropriate constructor error for nested list object in kotlin and JpaRepository

查看:168
本文介绍了无法在Kotlin和JpaRepository中为嵌套列表对象找到适当的构造函数错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当JPA尝试将查询的结果映射到结果存储库方法DTO时,我遇到以下错误:

I'm facing the following error when JPA attempts to map the result from a query to the result repository method 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-jpaorg.jetbrains.kotlin.plugin.jpa插件.我有一个这样定义的存储库:

I'm using spring-boot-starter-data-jpa and org.jetbrains.kotlin.plugin.jpa plugin in my Kotlin project. I have a repository defined like this:

@Repository
internal interface JdbcUserRepository : UserRepository, JpaRepository<DbUser, String> {

    override fun findUserByUsername(username: String): User?
}

请注意,JpaRepository(DbUser)使用的类型不同于findUserByUsername方法(User)重新调整的类型,并且在JPA( ... class [com. example.dto.User] ... ),但Role没有.期望目标DTO中出现DbRole,这是什么问题.

Note that type used by JpaRepository (DbUser) is different from the one retuned by the findUserByUsername method (User) and also on the error above the User class is correctly found by JPA (...class [com.example.dto.User]...) but Role doesn't. It's expecting a DbRole in the destination DTO, what is wrong.

DbUser是一个@Entity注释的类,它引用另一个称为DbRole的@Entity注释的类.两者都定义如下:

DbUser is an @Entity annotated class and refers to another @Entity annotated class called DbRole. Both are defined below:

@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必须将结果映射到的类:

And below are the classes where JPA must map results to:

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列表吗?

Does anybody know how to solve this problem and JPA correctly find and map the nested entity list of DbRole to the nested DTO list of Role?

推荐答案

问题是数据库查询只能返回纯结果.持久性提供程序可以将其转换为带有嵌套实体列表的实体.至于dto,您必须自己解决问题.

The problem is that database query is able to return plain result only. Persistence provider can convert it to entities with nested entities lists. As for dto you have to solve the problem yourself.

因此,您可以使用User dto和以下构造函数来获得简单的结果

So you can get plain result using User dto with constructor as below

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));  
}

然后您需要像这样的存储库方法

Then you need repository method like this

@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

这篇关于无法在Kotlin和JpaRepository中为嵌套列表对象找到适当的构造函数错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆