【问题标题】:Could any one tell me the real reason of spring-data projection in my case?谁能告诉我在我的情况下使用弹簧数据投影的真正原因?
【发布时间】:2017-10-23 04:39:24
【问题描述】:

案例是: 我有一个存储库和两个方法,其中一个看起来像:

//There is no warning about: Activity domain type or valid projection interface expected here...
@Query("select distinct a.creatorId from Activity a")
Optional<List<String>> findAllCreatorIds();

第二种方法如下:

//There i have warning about: Activity domain type or valid projection interface expected here
@Query("select distinct a.creatorId from Activity a join a.categories c where c.name in ?1")
Optional<List<String>> findAllCreatorIdsByCategoryNames(Set<String> categoryNames);

看起来可行,测试通过,生成的查询如下:

SELECT DISTINCT activity0_.created_by AS col_0_0_
FROM activities activity0_
INNER JOIN category_item categories1_ ON 
activity0_.id=categories1_.activity_id
INNER JOIN categories category2_ ON 
categories1_.category_id=category2_.id
WHERE category2_.name IN (?)

我已经进行了更改以使用投影界面。简单的投影界面是:

public interface CreatorIdProjection {
    String getCreatorId();
}

查询已更改:

@Query("select a from Activity a join a.categories c where c.name in ?1")
Optional<List<CreatorIdProjection>> findAllCreatorIdsByCategoryNames(Set<String> categoryNames);

也可以。这是生成的查询:

SELECT activity0_.id AS id1_0_,
       activity0_.price AS price2_0_,
       activity0_.created_by AS created_3_0_,
       activity0_.expiration_date AS expirati4_0_,
       activity0_.insertts AS insertts5_0_,
       activity0_.name AS name6_0_,
       activity0_.start_date AS start_da7_0_,
       activity0_.updatets AS updatets8_0_
FROM activities activity0_
INNER JOIN category_item categories1_ ON activity0_.id=categories1_.activity_id
INNER JOIN categories category2_ ON categories1_.category_id=category2_.id
WHERE category2_.name IN (?)

我有几个关于这个案例的问题:

  1. 为什么第一种方法没有警告?

  2. 为什么我们使用的时候查询在SELECT后有很多字段 投影? (更准确地说 - 为什么我们不能使用“选择 a.creatorId 来自 Activity a...")

  3. 警告“...域类型或有效的原因是什么? 此处应有投影界面”,如果结果我们有一个查询 查询表数据而不是我们需要的。

【问题讨论】:

  • 为什么要返回 Option> ? Optional 无论如何都不应该为空。
  • @JensSchauder,谢谢,我的错,结果集不会为空。我已经删除了 Optional 包装器,但是关于投影的图片是一样的。
  • 我无法重现警告。另外我在源代码中找不到警告。您能否提供完整的日志文件行,其中应包括类,可能还包括该日志语句的来源行。您使用的 Spring Data 版本也不错。
  • @JensSchauder,首先感谢您的回复。没有理由提供日志文件,我认为您完全正确,此警告与 Spring Data 框架无关,我检测到此警告是由我正在使用的 ide 产生的,我将联系开发人员或其他人一个来自支持澄清。

标签: java spring-boot spring-data hql h2


【解决方案1】:

关于问题 #1:

为什么第一种方法没有警告?

这里不涉及 Spring Data Projection。您只需执行一个查询,返回一个标量值列表,然后 Spring Data 将其传递(并包装在 Optional 中)。因此,您不应该收到这样的警告。事实上,我根本无法重现该警告,也无法在源代码中找到它,无论如何,第二种方法也适用相同的论点。如果它确实产生了这样的警告,请提交一个错误。

关于问题 #2a

为什么我们使用投影时查询在SELECT后有很多字段?

您使用@Query 注释准确地指定查询,它会被这样执行。 Spring Data 不会解析您的查询并删除不必要的部分,这将是一个巨大的努力,因为您首先提供了查询,所以您最好提供一个适合您需求的查询。

关于问题 #2b

为什么我们不能使用select a.creatorId from Activity a...

你(几乎)可以。您只需要指定别名,否则 JPA 会破坏列名,而 Spring Data 将不知道它正在查看哪些列。当您不指定别名时,它实际上会告诉您。你应该得到一个异常No aliases found in result tuple! Make sure your query defines aliases!。所以这应该有效:

select a.creatorId as creatorId from Activity a...

另一种方法是在语句中实际调用类的构造函数:

@Query("select new my.super.cool.projection.CreatorId(a.creatorId)")

两种变体都只会查询指定的列。

关于第 3 个问题

如果结果是我们有一个查询表数据而不是我们需要的查询,那么警告 ...domain type or valid projection interface expected here 的原因是什么。

我无法重现警告。我也搜了源码,没找到,所以无法回答这个问题。

【讨论】:

  • 感谢您对两个问题的明确回答,关于第三个问题,我将在这里发布来自创意团队的反馈。感谢您提到它与spring数据无关。
【解决方案2】:

警告的出现是因为您在方法名称中使用了“By”,这会触发 Spring Data 使用(魔术)查询方法。

删除“By”或将其替换为“Using”或其他内容,警告将消失。

另见https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.details

【讨论】:

  • 太棒了,真的很感激这个东西。
  • 此响应在执行操作时也对我有所帮助,而@Aggregation 触发了相同的警告。一个简单的方法重命名警告在 Intellij 中消失了
  • 在我的情况下,投影类没有 getter 和 setter,当我添加它们时警告消失了
猜你喜欢
  • 1970-01-01
  • 2020-09-06
  • 2022-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-12
  • 1970-01-01
相关资源
最近更新 更多