有人能告诉我在我的情况下弹簧数据投影的真正原因吗?

2022-09-04 05:02:03

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

//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中选择a.creatorId...”)

  3. 警告“...此处期望的域类型或有效投影接口“,如果因此我们有一个查询,查询表数据而不是我们需要的数据。


答案 1

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

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

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


答案 2

关于问题#1:

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

这里不涉及春季数据投影。您只需执行一个查询,返回标量值列表,然后该列表由Spring Data过去(并包装在)中。因此,您不应该收到这样的警告。事实上,我根本无法重现警告,也无法在源代码中找到它,无论如何,第二种方法的参数相同。如果它实际上产生了这样的警告,请提交一个错误。Optional

对于问题#2a

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

您可以完全使用批注指定查询,然后按此方式执行查询。Spring Data不会解析您的查询并删除不必要的部分,这将是一个巨大的努力,几乎没有什么影响,因为您首先提供了查询,您不妨提供一个适合您需求的查询。@Query

对于问题#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

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


推荐