Select 仅来自 Spring Data JPA 中连接表(多对多)的特定列
Select only specific columns from joined tables (Many-to-Many) in Spring Data JPA
目的是 select 连接的 table 列(多对多)。
我遇到的问题是 select 连接的多对多 table 中的两列 table.
我正在使用 Springboot 2.3 和 Spring 数据 Jpa。
我有这个数据模型,我要获取的是蓝色框的字段
所以本机查询可能看起来像这样(如果我是对的...)
SELECT bg.id, bg.name, p.name, c.name, c.short_desc FROM boardgame as bg
JOIN boardgame_category bgc on bg.id = bgc.fk_game
JOIN publisher p on bg.fk_publisher = p.id
JOIN category c on bgc.fk_category = c.id
WHERE bg.id = :id
我第一次尝试在 JPQL 语句中使用 dto
public class BoardgameDto {
private long id;
private String name;
private String publisherName;
private Set<CatregoryDto> categoryDto;
// setter, getter etc...
}
public class CategoryDto {
private String name;
private String shortDesc;
// setter, getter etc...
}
JQPL 查询可能看起来像这样,但它不起作用(IDE 在 CategoryDto 上显示错误)
/* THIS DOESN'T WORK */
SELECT new org.moto.tryingstuff.dto.BoardgameDto(bg.id, bg.name, p.name,
new org.moto.tryingstuff.dto.CategoryDto(c.name, c.short_desc)) FROM Boardgame as bg, Publisher as p, Category as c
好吧,我认为我这样做的问题是 dto 的构造函数无法接收集合 as written here,而且我认为参数中的另一个构造函数也没有。
然后我开始查看 Criteria Queries,特别是 multiselect、Tuple、Dto,但看起来我遇到了同样的问题,所以我没有深入研究它。
最后我使用了一个 JpaRepository,它是这样的 findById() 方法
public interface BoardgameRepository extends JpaRepository<Boardgame, Long> {
}
// In a test or service method
Boardgame game = repository.findById(long id);
然后我通过服务或控制器层的映射过滤我需要保留的字段。所以前面只收到了需要的数据。
不过感觉有点矫枉过正,
我是否遗漏了一些东西,框架的任何部分,只允许我 select 特定的列?
如您所写,您不能将集合用作构造函数表达式的参数。那是因为表达式被应用于结果集中的每条记录。这些记录是一个平面数据结构。它们不包含任何集合。您的数据库 returns 该集合中每个元素的新记录。
但是您的 constructor expression 失败的原因不同。您正在尝试组合 2 个构造函数表达式,但这是不受支持的。您需要删除第二个表达式并在 DTO 的构造函数中执行该操作。
因此,您的查询应如下所示:
SELECT new org.moto.tryingstuff.dto.BoardgameDto(bg.id, bg.name, p.name, c.name, c.short_desc) FROM Boardgame as bg <Your JOIN CLAUSES HERE>
你的 BoardgameD 的构造函数是这样的:
public class BoardgameDto {
public BoardgameDto(Long id, String gameName, String publisherName, String categoryName, String description) {
this.id = id;
this.name = gameName;
this.publisherName = publisherName;
this.category = new Category(categoryName, description);
}
...
}
目的是 select 连接的 table 列(多对多)。
我遇到的问题是 select 连接的多对多 table 中的两列 table.
我正在使用 Springboot 2.3 和 Spring 数据 Jpa。
我有这个数据模型,我要获取的是蓝色框的字段
所以本机查询可能看起来像这样(如果我是对的...)
SELECT bg.id, bg.name, p.name, c.name, c.short_desc FROM boardgame as bg
JOIN boardgame_category bgc on bg.id = bgc.fk_game
JOIN publisher p on bg.fk_publisher = p.id
JOIN category c on bgc.fk_category = c.id
WHERE bg.id = :id
我第一次尝试在 JPQL 语句中使用 dto
public class BoardgameDto {
private long id;
private String name;
private String publisherName;
private Set<CatregoryDto> categoryDto;
// setter, getter etc...
}
public class CategoryDto {
private String name;
private String shortDesc;
// setter, getter etc...
}
JQPL 查询可能看起来像这样,但它不起作用(IDE 在 CategoryDto 上显示错误)
/* THIS DOESN'T WORK */
SELECT new org.moto.tryingstuff.dto.BoardgameDto(bg.id, bg.name, p.name,
new org.moto.tryingstuff.dto.CategoryDto(c.name, c.short_desc)) FROM Boardgame as bg, Publisher as p, Category as c
好吧,我认为我这样做的问题是 dto 的构造函数无法接收集合 as written here,而且我认为参数中的另一个构造函数也没有。
然后我开始查看 Criteria Queries,特别是 multiselect、Tuple、Dto,但看起来我遇到了同样的问题,所以我没有深入研究它。
最后我使用了一个 JpaRepository,它是这样的 findById() 方法
public interface BoardgameRepository extends JpaRepository<Boardgame, Long> {
}
// In a test or service method
Boardgame game = repository.findById(long id);
然后我通过服务或控制器层的映射过滤我需要保留的字段。所以前面只收到了需要的数据。
不过感觉有点矫枉过正,
我是否遗漏了一些东西,框架的任何部分,只允许我 select 特定的列?
如您所写,您不能将集合用作构造函数表达式的参数。那是因为表达式被应用于结果集中的每条记录。这些记录是一个平面数据结构。它们不包含任何集合。您的数据库 returns 该集合中每个元素的新记录。
但是您的 constructor expression 失败的原因不同。您正在尝试组合 2 个构造函数表达式,但这是不受支持的。您需要删除第二个表达式并在 DTO 的构造函数中执行该操作。
因此,您的查询应如下所示:
SELECT new org.moto.tryingstuff.dto.BoardgameDto(bg.id, bg.name, p.name, c.name, c.short_desc) FROM Boardgame as bg <Your JOIN CLAUSES HERE>
你的 BoardgameD 的构造函数是这样的:
public class BoardgameDto {
public BoardgameDto(Long id, String gameName, String publisherName, String categoryName, String description) {
this.id = id;
this.name = gameName;
this.publisherName = publisherName;
this.category = new Category(categoryName, description);
}
...
}