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.QuerySyntaxE
Why does your JdbcUserRepository
returns a User
object for findUserByUsername
and not a DbUser
? The solution should be obvious:
override fun findUserByUsername(username: String): DbUser?
And you do the mapping afterwards manually.
You should think that people know why they introduced multiple representations of the same object instead of using a single representation as long as possible...
I had to do an adtional step of casting like so cast(ds.demoId as java.lang.String)
check this out :
@Query( value = "select new com.api.models.DsResultStatus("+
"cast(ds.demoId as java.lang.String),cast(ds.comp as java.lang.String),cast(ds.dc as java.lang.String),cast(be.buildUrl as java.lang.String)" +
",cast(be.username as java.lang.String),cast(tr.title as java.lang.String),cast(tr.result as java.lang.String)) \n" +
"from DsEntity ds \n" +
"inner join BtEntity be ON ds.id = be.demoAssGuardingEntity\n" +
"inner join TrEntity tr ON be.id = tr.buildEntity\n" +
"where ds.demoId in (?1) " +
"and tr.title in ('\"Amazon\"','\"Google\"','\"FB\"') and tr.result = '\"failed\"'")
List<DemoAssGuardingBuildResultStatus> getAssIdsWithFaliures(@Param("demoIds") Set<String> demoIds);
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.
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);
Handle result in service layer
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);
}
You can use the same approach for Kotlin