谁能告诉我 spring-data projection 在我的案例中的真正原因?
Could any one tell me the real reason of spring-data projection in my case?
案例是:
我有一个存储库和两种方法,其中一种看起来像:
//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 (?)
关于这个案例我有几个问题:
为什么第一种方法没有警告?
为什么我们使用SELECT后查询的字段很多
投影? (更准确地说 - 为什么我们不能使用“select
a.creatorId 来自 Activity a...")
警告“...域类型或有效”的原因是什么
预计这里有投影界面”,如果结果我们有一个查询
查询 table 数据而不是我们需要的数据。
关于问题 #1:
Why there is no warning for the first method?
这里不涉及Spring数据投影。您只需执行一个返回标量值列表的查询,然后由 Spring 数据传递(并包装在 Optional
中)。因此你不应该得到这样的警告。事实上,我根本无法重现该警告,也无法在源代码中找到它,无论如何,同样的论点适用于第二种方法。如果它确实产生了这样的警告,请提交错误。
对于问题 #2a
Why the query have a lot of fields after SELECT when we use projection?
您使用 @Query
注释准确指定查询,它会按原样执行。 Spring Data 不会解析您的查询并删除不必要的部分,这将是一项巨大的努力,但收效甚微,因为您首先提供了查询,您不妨提供一个适合您需要的查询。
对于问题 #2b
why we cannot use 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...
另一种方法是在语句中实际调用 class 的构造函数:
@Query("select new my.super.cool.projection.CreatorId(a.creatorId)")
两种变体都将只查询指定的列。
对于问题 #3
What is the reason for the warning ...domain type or valid projection interface expected here
if as a result we have a query that querying the table data instead of what we need.
我无法重现警告。我也搜了下源码也没找到,所以这个没法回答
出现警告是因为您在方法名称中使用了 'By',这会触发 Spring 要使用的数据(魔术)查询方法。
删除 'By' 或将其替换为 'Using' 或其他内容,警告将消失。
案例是: 我有一个存储库和两种方法,其中一种看起来像:
//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 (?)
关于这个案例我有几个问题:
为什么第一种方法没有警告?
为什么我们使用SELECT后查询的字段很多 投影? (更准确地说 - 为什么我们不能使用“select a.creatorId 来自 Activity a...")
警告“...域类型或有效”的原因是什么 预计这里有投影界面”,如果结果我们有一个查询 查询 table 数据而不是我们需要的数据。
关于问题 #1:
Why there is no warning for the first method?
这里不涉及Spring数据投影。您只需执行一个返回标量值列表的查询,然后由 Spring 数据传递(并包装在 Optional
中)。因此你不应该得到这样的警告。事实上,我根本无法重现该警告,也无法在源代码中找到它,无论如何,同样的论点适用于第二种方法。如果它确实产生了这样的警告,请提交错误。
对于问题 #2a
Why the query have a lot of fields after SELECT when we use projection?
您使用 @Query
注释准确指定查询,它会按原样执行。 Spring Data 不会解析您的查询并删除不必要的部分,这将是一项巨大的努力,但收效甚微,因为您首先提供了查询,您不妨提供一个适合您需要的查询。
对于问题 #2b
why we cannot use
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...
另一种方法是在语句中实际调用 class 的构造函数:
@Query("select new my.super.cool.projection.CreatorId(a.creatorId)")
两种变体都将只查询指定的列。
对于问题 #3
What is the reason for the warning
...domain type or valid projection interface expected here
if as a result we have a query that querying the table data instead of what we need.
我无法重现警告。我也搜了下源码也没找到,所以这个没法回答
出现警告是因为您在方法名称中使用了 'By',这会触发 Spring 要使用的数据(魔术)查询方法。
删除 'By' 或将其替换为 'Using' 或其他内容,警告将消失。