Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/369.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 处理JPA期间查询的正确方法是什么?_Java_Postgresql_Hibernate_Jpa - Fatal编程技术网

Java 处理JPA期间查询的正确方法是什么?

Java 处理JPA期间查询的正确方法是什么?,java,postgresql,hibernate,jpa,Java,Postgresql,Hibernate,Jpa,我需要生成下面的预期结果。基本上,它是一个查询,根据特定的周期每周、每月等聚合值。有一个日期过滤器,有开始和结束,我们需要返回所有范围的值。如果它们不存在,则应返回0 在下例中,开始日期为“2015-08-02”,日期为“2015-08-23”,期间为每周。请注意,对于第2周,我们没有值,但应该返回一个零值 那么,在这种情况下,使用JPA实现这一点的最佳方法是什么?我们考虑使用临时表并将结果与此表连接以获得整个范围的结果,但我不知道使用JPA是否可行,因为我们需要创建表、连接然后销毁临时表 另一

我需要生成下面的预期结果。基本上,它是一个查询,根据特定的周期每周、每月等聚合值。有一个日期过滤器,有开始和结束,我们需要返回所有范围的值。如果它们不存在,则应返回0

在下例中,开始日期为“2015-08-02”,日期为“2015-08-23”,期间为每周。请注意,对于第2周,我们没有值,但应该返回一个零值

那么,在这种情况下,使用JPA实现这一点的最佳方法是什么?我们考虑使用临时表并将结果与此表连接以获得整个范围的结果,但我不知道使用JPA是否可行,因为我们需要创建表、连接然后销毁临时表

另一个选项是创建数据库视图并将其映射到实体

在上述情况下,JPQL查询应该是这样的:

@Query("select status, sum(totalInvoice), week from Invoice where " +
        "left join TempTable as tt..." + <-- TEMP TABLE OR VIEW TO GET THE PERIODS
        "issuer.id = :issuerId and type = :type and (:recipientId is null or recipient.id = :recipientId) and " +
        "status in ('ISSUED', 'PAID') " +
        "group by status")
另一种选择是使用存储过程,但它们似乎很难用JPA实现,我认为它们不是必需的

预期结果:

{  
   "code":"xxx",
   "title":"This is the title of the first series"
   "type":"PERIODIC",
   "period":"WEEKLY", <-- PERIOD
   "from":"2015-08-02",
   "to":"2015-08-29",
   "labels": ["2015-08-02", "2015-08-09", "2015-08-16", "2015-08-23"],
   "tabelType": "TEXT",
   "series":[  
      {  
         "code":"xxx",
         "title":"This is the title of the first series"
         "values":[10, 0, 13, 18] <- in this example, we don't have values for label "2015-08-09"
      },
      {  
         "code":"xxx",
         "title":"This is the title of the second series"
         "values":[10, 0, 13, 18] <- in this example, we don't have values for label "2015-08-09"
      }
   ]
}

这可能不是您问题的直接答案,但是:为什么您需要直接在JPA查询中进行分组,而不是在Java代码中进行分组?这种类型的复杂语义分组在使用Java时做得非常好,但SQL数据库通常不擅长生成这种类型的结构化数据。如果没有其他理由在数据库级别执行此操作,例如,您需要一个填充了此数据的视图,该视图可根据时间段进行搜索,然后,只需加载原始数据并使用Java代码填充结构-这样会大大减少编码开销,并且可能会更高效。

这可能不是您问题的直接答案,但是:为什么您需要直接在JPA查询中而不是在Java代码中进行分组?这种类型的复杂语义分组在使用Java时做得非常好,但SQL数据库通常不擅长生成这种类型的结构化数据。如果没有其他理由在数据库级别上这样做,比如说,您需要一个填充了该数据的视图,该视图可以基于句点进行搜索,然后只需加载原始数据并使用Java代码填充结构-它将大大减少编码开销,并且可能会更高效。

@pozs在这里提供了答案。这只能通过本机查询PostgreSQL完成。结果如下:

/**
 * Returns the counts, totals and averages of the states by their currency, period and status.
 */
@Query(value = "select i.currency, date(p), i.status, count(id), sum(coalesce(i.total, 0)), avg(coalesce(i.total, 0)) " +
    "from generate_series(date_trunc(:period, cast(:from as timestamp)), date_trunc(:period, cast(:to as timestamp)) + cast('1 ' || :period as interval), cast('1 ' || :period as interval)) p " +
    "inner join invoice i on i.due_date >= p and i.due_date < p + cast('1 ' || :period as interval) " +
    "where issuer_id = :issuerId and type = :type and (:recipientId = 0 or recipient_id = :recipientId) and type = :type " +
    "group by i.currency,  date(p), i.status " +
    "order by i.currency, date(p), i.status", nativeQuery = true)
List<Object[]> getIssuerStatementTotalsByCurrencyPeriodAndStatus(
    @Param("issuerId") long issuerId,
    @Param("recipientId") long recipientId,
    @Param("type") String statementType,
    @Param("from") String from,
    @Param("to") String to,
    @Param("period") String period);
请注意,这将返回对象数组的列表。还要注意,我无法将枚举和复杂参数传递到方法中。我不得不将这些值简化为字符串和原语

我已经通过以下课程将此结果转化为有意义的内容:

  /**
   * Contains the result of a single result in an aggregate query.
   */
  public class AggregateResult {

      private List<String> keys;
      private List<BigDecimal> values;

      @SuppressWarnings("unused")
      public AggregateResult(Object value1, Object value2) {
          this(new Object[] { value1, value2 });
      }

      @SuppressWarnings("unused")
      public AggregateResult(Object value1, Object value2, Object value3) {
          this(new Object[] { value1, value2, value3 });
      }

      @SuppressWarnings("unused")
      public AggregateResult(Object value1, Object value2, Object value3, Object value4) {
          this(new Object[] { value1, value2, value3, value4 });
      }

      @SuppressWarnings("unused")
      public AggregateResult(Object value1, Object value2, Object value3, Object value4, Object value5) {
          this(new Object[] { value1, value2, value3, value4, value5 });
      }

      public AggregateResult(Object... vals) {
          values = new ArrayList<>();
          while (values.size() < vals.length && vals[vals.length - values.size() - 1] instanceof Number) {
              Number number = (Number) vals[vals.length - values.size() - 1];
              values.add(number instanceof BigDecimal ? (BigDecimal) number : new BigDecimal(number.toString()));
          }

          this.keys = Stream.of(ArrayUtils.subarray(vals, 0, vals.length - values.size())).map(Object::toString).collect(toList());
      }

      public List<String> getKeys() {
          return keys;
      }

      public List<BigDecimal> getValues() {
          return values;
      }

      /**
       * Returns the list of {@link AggregateResult}s for the raw result. The raw result is expected to
       * have been returned from a native JPA query.
       */
      public static List<AggregateResult> fromNativeResult(List<Object[]> raw) {
          return raw.stream().map(AggregateResult::new).collect(toList());
      }
  }

@pozs在这里提供了答案。这只能通过本机查询PostgreSQL完成。结果如下:

/**
 * Returns the counts, totals and averages of the states by their currency, period and status.
 */
@Query(value = "select i.currency, date(p), i.status, count(id), sum(coalesce(i.total, 0)), avg(coalesce(i.total, 0)) " +
    "from generate_series(date_trunc(:period, cast(:from as timestamp)), date_trunc(:period, cast(:to as timestamp)) + cast('1 ' || :period as interval), cast('1 ' || :period as interval)) p " +
    "inner join invoice i on i.due_date >= p and i.due_date < p + cast('1 ' || :period as interval) " +
    "where issuer_id = :issuerId and type = :type and (:recipientId = 0 or recipient_id = :recipientId) and type = :type " +
    "group by i.currency,  date(p), i.status " +
    "order by i.currency, date(p), i.status", nativeQuery = true)
List<Object[]> getIssuerStatementTotalsByCurrencyPeriodAndStatus(
    @Param("issuerId") long issuerId,
    @Param("recipientId") long recipientId,
    @Param("type") String statementType,
    @Param("from") String from,
    @Param("to") String to,
    @Param("period") String period);
请注意,这将返回对象数组的列表。还要注意,我无法将枚举和复杂参数传递到方法中。我不得不将这些值简化为字符串和原语

我已经通过以下课程将此结果转化为有意义的内容:

  /**
   * Contains the result of a single result in an aggregate query.
   */
  public class AggregateResult {

      private List<String> keys;
      private List<BigDecimal> values;

      @SuppressWarnings("unused")
      public AggregateResult(Object value1, Object value2) {
          this(new Object[] { value1, value2 });
      }

      @SuppressWarnings("unused")
      public AggregateResult(Object value1, Object value2, Object value3) {
          this(new Object[] { value1, value2, value3 });
      }

      @SuppressWarnings("unused")
      public AggregateResult(Object value1, Object value2, Object value3, Object value4) {
          this(new Object[] { value1, value2, value3, value4 });
      }

      @SuppressWarnings("unused")
      public AggregateResult(Object value1, Object value2, Object value3, Object value4, Object value5) {
          this(new Object[] { value1, value2, value3, value4, value5 });
      }

      public AggregateResult(Object... vals) {
          values = new ArrayList<>();
          while (values.size() < vals.length && vals[vals.length - values.size() - 1] instanceof Number) {
              Number number = (Number) vals[vals.length - values.size() - 1];
              values.add(number instanceof BigDecimal ? (BigDecimal) number : new BigDecimal(number.toString()));
          }

          this.keys = Stream.of(ArrayUtils.subarray(vals, 0, vals.length - values.size())).map(Object::toString).collect(toList());
      }

      public List<String> getKeys() {
          return keys;
      }

      public List<BigDecimal> getValues() {
          return values;
      }

      /**
       * Returns the list of {@link AggregateResult}s for the raw result. The raw result is expected to
       * have been returned from a native JPA query.
       */
      public static List<AggregateResult> fromNativeResult(List<Object[]> raw) {
          return raw.stream().map(AggregateResult::new).collect(toList());
      }
  }

在Postgres中,这通常是用来完成的,但是除了使用本机查询之外,我想不出一种JPA友好的方式。@pozs,是的,如何在JPA上完成这项工作是最困难的部分。我在想,也许可以使用映射到JPA实体的视图,但我不知道是否可行。在Postgres中,这通常是用来完成的,但是除了使用本机查询之外,我想不出一种JPA友好的方式。@pozs,是的,如何在JPA上实现这一点是最困难的部分。我在想也许使用一个映射到JPA实体的视图,但我不知道它是否有效。谢谢你的回答,但我认为用Java代码做这类事情应该会慢一些。通常SQL的速度相当快。这完全取决于您想要执行的操作类型。然而,由于Java是在内存中运行的,SQL服务器通常除了缓存的查询/索引之外不会运行,因此经过良好编程的Java代码通常比其SQL等价物要快。然而,当涉及到各种类型的临时分组时,在大多数情况下,Java将比SQL更快。此外,您还必须记住代码清晰性和可管理性的潜在成本。即使数据库解决方案更快,问题是您是否愿意为更难阅读和维护的解决方案付出代价。谢谢您的回答,但我认为用Java代码来完成这类工作应该更慢。通常SQL的速度相当快。这完全取决于您想要执行的操作类型。然而,由于Java是在内存中运行的,SQL服务器通常除了缓存的查询/索引之外不会运行,因此经过良好编程的Java代码通常比其SQL等价物要快。然而,当涉及到各种类型的临时分组时,在大多数情况下,Java将比SQL更快。还有,y 您必须记住代码清晰性和可管理性的潜在成本。即使数据库解决方案更快,问题是您是否愿意为更难阅读和维护的解决方案付出代价。