I have a query made with querydsl, in the query I extract a field as an enum, but running the query it throws this error:
org.hibernate.query.sqm.sql.ConversionException: Could not determine ValueMapping for SqmParameter: SqmPositionalParameter(2)
The problem seems related to the conversion of the enum. The query is something like this:
query.select(new QTestDto(qTE.id,
Expressions.cases()
.when(qTE.code.startsWith("A"))
.then(TestType.GOOD)
.otherwise(TestType.BAD)))
.from(qTE)
.fetch();
If I change the projected objects TestDto, using a string instead an enum, and I change the extraction with toString(), it works, but I would like to use directly the enum.
This is a unit test to reproduce the error:
import com.querydsl.core.annotations.QueryProjection;
import com.querydsl.core.types.ConstructorExpression;
import com.querydsl.core.types.Path;
import com.querydsl.core.types.PathMetadata;
import com.querydsl.core.types.dsl.EntityPathBase;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.core.types.dsl.NumberPath;
import com.querydsl.core.types.dsl.StringPath;
import com.querydsl.jpa.impl.JPAQuery;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import java.io.Serial;
import static com.querydsl.core.types.PathMetadataFactory.forVariable;
import static org.assertj.core.api.Assertions.assertThat;
@DataJpaTest
class CaseBuilderTest {
@Autowired
private EntityManager em;
@Test
void test() {
// given
em.persist(new TestEntity(1L, "A003", "Description ..."));
em.persist(new TestEntity(2L, "B538", "Description ..."));
// when
var qTE = QTestEntity.testEntity;
var query = new JPAQuery<TestDto>(em);
var result = query.select(new QTestDto(qTE.id,
Expressions.cases()
.when(qTE.code.startsWith("A"))
.then(TestType.GOOD)
.otherwise(TestType.BAD)))
.from(qTE)
.fetch();
// then
assertThat(result).hasSize(2);
}
@Getter
@Setter
public static class TestDto {
private Long id;
private TestType type;
@QueryProjection
public TestDto(Long id, TestType type) {
this.id = id;
this.type = type;
}
}
@Entity
@AllArgsConstructor
@NoArgsConstructor
public static class TestEntity {
@Id
@Column
private Long id;
@Column
private String code;
@Column
private String description;
}
public enum TestType {
GOOD,
BAD;
}
// Generated
public static class QTestEntity extends EntityPathBase<TestEntity> {
@Serial
private static final long serialVersionUID = 1L;
public static final QTestEntity testEntity = new QTestEntity("testEntity");
public final StringPath code = createString("code");
public final StringPath description = createString("description");
public final NumberPath<Long> id = createNumber("id", Long.class);
public QTestEntity(String variable) {
super(TestEntity.class, forVariable(variable));
}
public QTestEntity(Path<? extends TestEntity> path) {
super(path.getType(), path.getMetadata());
}
public QTestEntity(PathMetadata metadata) {
super(TestEntity.class, metadata);
}
}
// Generated
public static class QTestDto extends ConstructorExpression<TestDto> {
@Serial
private static final long serialVersionUID = 1L;
public QTestDto(com.querydsl.core.types.Expression<Long> id, com.querydsl.core.types.Expression<TestType> type) {
super(TestDto.class, new Class<?>[] {long.class, TestType.class}, id, type);
}
}
}
What am I doing wrong?