如何在Micronaut数据存储库中使用@Query进行结果查询,其中结果具有多个列?

发布于 2025-01-29 03:23:38 字数 3678 浏览 6 评论 0原文

我完成了本教程:

​ 子句组的组。然后我的代码看起来像这样: 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

掩于岁月 2025-02-05 03:23:38

我的问题是,我的课程中没有@Intropsected注释,代表查询结果。对于Java来说,有点陌生,对Micronaut非常陌生,我不知道Micronaut的某些要求,例如您必须以某种方式进行某种方式,以便它在编译时完成工作。豆自省是其中的一部分。

因此,我将查询结果类(实际上使用的记录)更改为:

package example.micronaut.dtos;

import io.micronaut.core.annotation.Introspected;

@Introspected
public record PopularProductResult(
        String productId,
        Long count) {
}

此时,我有一个不同的错误:

内部服务器错误:错误读取名称的错误对象[product_id]从结果集:列'product_id'找不到。

这是由我与@query一起使用的查询引起的:

@Query("SELECT product_id AS productId, COUNT(*) AS count FROM `view` GROUP BY productId ORDER BY count DESC")
List<PopularProductResult> popularViews();

我的查询结果列名称应与我的Java类中定义的字段匹配。取而代之的是,Micronaut正在做自己的名称映射,它在我的结果集中寻找product_id的列名称,因为我的字段名称为productID。在 https中, -projects.github.io/micronaut-data/latest/guide/#sqlnaming

因此,我将查询更改为:

@Query("SELECT product_id, COUNT(*) AS count FROM `view` GROUP BY product_id ORDER BY count DESC")
List<PopularProductResult> popularViews();

我得到了我正在寻找的结果,没有错误:

[
  {
    "productId": "abc123",
    "count": 85
  },
  {
    "productId": "ghi789",
    "count": 81
  },
  {
    "productId": "def456",
    "count": 78
  }
]

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:

package example.micronaut.dtos;

import io.micronaut.core.annotation.Introspected;

@Introspected
public record PopularProductResult(
        String productId,
        Long count) {
}

At this point, I had a different error:

Internal Server Error: Error reading object for name [product_id] from result set: Column 'product_id' not found.

It was caused by my query used with @Query:

@Query("SELECT product_id AS productId, COUNT(*) AS count FROM `view` GROUP BY productId ORDER BY count DESC")
List<PopularProductResult> popularViews();

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 was productId. 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:

@Query("SELECT product_id, COUNT(*) AS count FROM `view` GROUP BY product_id ORDER BY count DESC")
List<PopularProductResult> popularViews();

And I got the results I was looking for, without errors:

[
  {
    "productId": "abc123",
    "count": 85
  },
  {
    "productId": "ghi789",
    "count": 81
  },
  {
    "productId": "def456",
    "count": 78
  }
]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文