如何在Micronaut数据存储库中使用@Query进行结果查询,其中结果具有多个列?
我完成了本教程:
子句组的组。然后我的代码看起来像这样: https://github.com /mattwelke/micronaut-jdbc-guide-complete/tree/rec-ingine (请注意分支名称rec-engine
)
当我运行脚本./ scripts/stripts/starts_mysql时。 sh
然后运行curl http:// localhost:8080/views/pocul
在应用程序运行时,我会返回以下错误(在日志中):
{
"message":"Internal Server Error",
"_embedded":{
"errors":[
{
"message":"Internal Server Error: Cannot convert type [class java.lang.String] with value [def456] to target type: class example.micronaut.dtos.PopularProductResult. Consider defining a TypeConverter bean to handle this case."
}
]
},
"_links":{
"self":{
"href":"/views/popular",
"templated":false
}
}
}
我是:我是在Micronaut数据将负责此映射的印象中。但是我也知道,Micronaut数据是否没有能力这样做,我需要自己做。但是,当我自己尝试执行此操作时,我对如何按照说明创建一些代码来将查询结果映射到我的课程中。该错误将字符串
映射到poasterproductresult
(我的类)。我不想将字符串映射到该类。我想将字符串和数字映射到该类,因为它代表了一个聚合结果。
我该怎么做?
GitHub存储库显示了完整的代码,但是在此处轻松参考,这是我的域模型,存储库(包括@query
中的查询)和我的自定义类别的查询结果:
package example.micronaut.domain;
import io.micronaut.data.annotation.GeneratedValue;
import io.micronaut.data.annotation.Id;
import io.micronaut.data.annotation.MappedEntity;
import javax.validation.constraints.NotNull;
@MappedEntity
public class View {
@Id
@GeneratedValue(GeneratedValue.Type.AUTO)
private Long id;
@NotNull
private String productId;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getProductId() {
return productId;
}
public void setProductId(String productId) {
this.productId = productId;
}
@Override
public String toString() {
return "View{" +
"id=" + id +
", productId='" + productId + '\'' +
'}';
}
}
package example.micronaut;
import example.micronaut.domain.View;
import example.micronaut.dtos.PopularProductResult;
import io.micronaut.core.annotation.NonNull;
import io.micronaut.data.annotation.Id;
import io.micronaut.data.annotation.Query;
import io.micronaut.data.exceptions.DataAccessException;
import io.micronaut.data.jdbc.annotation.JdbcRepository;
import io.micronaut.data.model.query.builder.sql.Dialect;
import io.micronaut.data.repository.PageableRepository;
import java.util.List;
import javax.transaction.Transactional;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@JdbcRepository(dialect = Dialect.MYSQL)
public interface ViewRepository extends PageableRepository<View, Long> {
View save(@NonNull @NotBlank String productId);
@Transactional
default View saveWithException(@NonNull @NotBlank String productId) {
save(productId);
throw new DataAccessException("test exception");
}
long update(@NonNull @NotNull @Id Long id, @NonNull @NotBlank String productId);
@Query("SELECT product_id AS productId, COUNT(*) AS count FROM `view` GROUP BY productId ORDER BY count DESC")
List<PopularProductResult> popularViews();
}
package example.micronaut.dtos;
public record PopularProductResult(String productId, Long count) {
}
I completed this tutorial: https://guides.micronaut.io/latest/micronaut-data-jdbc-repository-gradle-java.html
I then added code to the completed, working tutorial to try to do a custom SQL query for a use case involving reading the data with a GROUP BY
clause. My code then looked like this: https://github.com/mattwelke/micronaut-jdbc-guide-complete/tree/rec-engine (note the branch name rec-engine
)
When I run the script ./scripts/start_mysql.sh
and then run curl http://localhost:8080/views/popular
in another terminal while the application runs, I get the following error returned (and in the logs):
{
"message":"Internal Server Error",
"_embedded":{
"errors":[
{
"message":"Internal Server Error: Cannot convert type [class java.lang.String] with value [def456] to target type: class example.micronaut.dtos.PopularProductResult. Consider defining a TypeConverter bean to handle this case."
}
]
},
"_links":{
"self":{
"href":"/views/popular",
"templated":false
}
}
}
I was under the impression that Micronaut Data would take care of this mapping. But I also understand if Micronaut Data isn't capable of doing this, and I'm required to do it myself. however, when I try to do it myself, I'm confused about how to follow the instructions to create some code that would map the query results to my class. The error describes mapping a String
to PopularProductResult
(my class). I don't want to map a string to that class. I want to map a string and a number to that class, since it represents an aggregation result.
How do I do this?
The GitHub repo shows the complete code, but for easy reference here, here's my domain model, repository (including the query in the @Query
) and my custom class for my query results:
package example.micronaut.domain;
import io.micronaut.data.annotation.GeneratedValue;
import io.micronaut.data.annotation.Id;
import io.micronaut.data.annotation.MappedEntity;
import javax.validation.constraints.NotNull;
@MappedEntity
public class View {
@Id
@GeneratedValue(GeneratedValue.Type.AUTO)
private Long id;
@NotNull
private String productId;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getProductId() {
return productId;
}
public void setProductId(String productId) {
this.productId = productId;
}
@Override
public String toString() {
return "View{" +
"id=" + id +
", productId='" + productId + '\'' +
'}';
}
}
package example.micronaut;
import example.micronaut.domain.View;
import example.micronaut.dtos.PopularProductResult;
import io.micronaut.core.annotation.NonNull;
import io.micronaut.data.annotation.Id;
import io.micronaut.data.annotation.Query;
import io.micronaut.data.exceptions.DataAccessException;
import io.micronaut.data.jdbc.annotation.JdbcRepository;
import io.micronaut.data.model.query.builder.sql.Dialect;
import io.micronaut.data.repository.PageableRepository;
import java.util.List;
import javax.transaction.Transactional;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@JdbcRepository(dialect = Dialect.MYSQL)
public interface ViewRepository extends PageableRepository<View, Long> {
View save(@NonNull @NotBlank String productId);
@Transactional
default View saveWithException(@NonNull @NotBlank String productId) {
save(productId);
throw new DataAccessException("test exception");
}
long update(@NonNull @NotNull @Id Long id, @NonNull @NotBlank String productId);
@Query("SELECT product_id AS productId, COUNT(*) AS count FROM `view` GROUP BY productId ORDER BY count DESC")
List<PopularProductResult> popularViews();
}
package example.micronaut.dtos;
public record PopularProductResult(String productId, Long count) {
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我的问题是,我的课程中没有
@Intropsected
注释,代表查询结果。对于Java来说,有点陌生,对Micronaut非常陌生,我不知道Micronaut的某些要求,例如您必须以某种方式进行某种方式,以便它在编译时完成工作。豆自省是其中的一部分。因此,我将查询结果类(实际上使用的记录)更改为:
此时,我有一个不同的错误:
这是由我与
@query
一起使用的查询引起的:我的查询结果列名称应与我的Java类中定义的字段匹配。取而代之的是,Micronaut正在做自己的名称映射,它在我的结果集中寻找
product_id
的列名称,因为我的字段名称为productID
。在 https中, -projects.github.io/micronaut-data/latest/guide/#sqlnaming 。因此,我将查询更改为:
我得到了我正在寻找的结果,没有错误:
My problem was that I didn't have the
@Introspected
annotation on my class representing query results. Being somewhat new to Java and very new to Micronaut, I wasn't aware of some of the requirements Micronaut has, like how you have to do things a certain way so that it does its work at compile time. Bean introspection is a part of that.So I changed my query result class (which I'm actually using a record for) to:
At this point, I had a different error:
It was caused by my query used with
@Query
:I was under the impression my query result column names should match the fields defined in my Java class. Instead, Micronaut was doing its own name mapping where it was looking for a column name called
product_id
in my result set because my field name wasproductId
. This behaviour is described in the Micronaut Data documentation at https://micronaut-projects.github.io/micronaut-data/latest/guide/#sqlNaming.So I changed my query to:
And I got the results I was looking for, without errors: