JPQL JOIN FETCH 多个表也带有空集合
Posted
技术标签:
【中文标题】JPQL JOIN FETCH 多个表也带有空集合【英文标题】:JPQL JOIN FETCH multiple tables also with empty collections 【发布时间】:2016-10-07 04:01:45 【问题描述】:我只是想获得一个具有所有属性的完整实体,包括空集合(如果它们是空的)。
public class Users extends BaseEntity
...
@Column(name = "Prename")
private String prename;
@Column(name = "session")
private String session;
@JsonView( View.Users.class )
@ManyToMany(cascade = CascadeType.PERSIST, CascadeType.MERGE , fetch = FetchType.LAZY)
@JoinTable(
name="USERS_PROJECTS",
joinColumns=@JoinColumn(name="USERS_ID", referencedColumnName="id"),
inverseJoinColumns=@JoinColumn(name="PROJECT_ID", referencedColumnName="id"))
private Set<Project> projects = new HashSet<>();
@JsonView( View.Users.class )
@ManyToMany(mappedBy = "projectManager",
cascade = CascadeType.PERSIST, CascadeType.MERGE ,
fetch = FetchType.LAZY)
private Set<Project> managingProjects = new HashSet<>();
@JsonView( View.Users.class )
@ManyToMany(mappedBy = "projectManager",
cascade = CascadeType.PERSIST, CascadeType.MERGE ,
fetch = FetchType.LAZY)
private Set<Project> watchingProjects = new HashSet<>();
...
对应的命名查询如下所示:
@NamedQueries(
@NamedQuery(
name = Users.QUERY_GET_ALL_USERS_ASC,
query = "SELECT u " +
"FROM Users u " +
"LEFT JOIN FETCH u.projects proj " +
"LEFT JOIN FETCH u.managingProjects manProj " +
"LEFT JOIN FETCH u.watchingProjects watProj " +
"ORDER BY u.email ASC")
)
这个查询返回大约 350 个对象,而它应该只返回 17 个,可能是因为它不是“GROUPED”。
@NamedQueries(
@NamedQuery(
name = Users.QUERY_GET_ALL_USERS_ASC,
query = "SELECT u " +
"FROM Users u " +
"JOIN FETCH u.projects proj " +
"JOIN FETCH u.managingProjects manProj " +
"JOIN FETCH u.watchingProjects watProj " +
"ORDER BY u.email ASC")
)
此查询返回 0 个对象,因为并非每个对象都与非空的 watchProjects 或 managementProjects 集合相关。
@NamedQuery(
name = Users.QUERY_GET_ALL_USERS_ASC,
query = "SELECT u " +
"FROM Users u " +
"LEFT JOIN FETCH u.projects proj " +
"LEFT JOIN FETCH u.managingProjects manProj " +
"LEFT JOIN FETCH u.watchingProjects watProj " +
"GROUP BY u " // + ", manProj, watProj " + // does not change anything
"ORDER BY u.email ASC")
此查询引发以下异常:
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.1.v20150605-31e8258): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: column "t1.id" must appear in the GROUP BY clause or be used in an aggregate function
Position: 99
Error Code: 0
Call: SELECT t0.ID, t0.CreateDate, t0.EMail, t0.Lastname, t0.Password, t0.Prename, t0.Role, t0.session, t1.ID, t1.Name, t1.Scheme, t2.ID, t2.Name, t2.Scheme, t3.ID, t3.Name, t3.Scheme FROM Users t0 LEFT OUTER JOIN (USERS_PROJECTS t6 JOIN PROJECT t1 ON (t1.ID = t6.PROJECT_ID)) ON (t6.USERS_ID = t0.ID) LEFT OUTER JOIN (PROJECTS_MANAGER t7 JOIN PROJECT t2 ON (t2.ID = t7.PROJECT_ID)) ON (t7.MANAGER_ID = t0.ID) LEFT OUTER JOIN (PROJECTS_MANAGER t8 JOIN PROJECT t3 ON (t3.ID = t8.PROJECT_ID)) ON (t8.MANAGER_ID = t0.ID) LEFT OUTER JOIN (PROJECTS_MANAGER t9 JOIN PROJECT t4 ON (t4.ID = t9.PROJECT_ID)) ON (t9.MANAGER_ID = t0.ID) LEFT OUTER JOIN (PROJECTS_MANAGER t10 JOIN PROJECT t5 ON (t5.ID = t10.PROJECT_ID)) ON (t10.MANAGER_ID = t0.ID) GROUP BY t0.ID, t0.CreateDate, t0.EMail, t0.Lastname, t0.Password, t0.Prename, t0.Role, t0.session, t4.ID, t4.Name, t4.Scheme, t5.ID, t5.Name, t5.Scheme ORDER BY t0.EMail ASC
将 FetchType 设置为 LAZY 不是一个选项,因为还有其他查询不应该获取这些属性。所以问题是如何返回所有带有可能为空集合的 JPQL 查询的实体? 我正在使用 EclipseLink 2.6.2 和 JPA 2.1。
【问题讨论】:
使用SELECT u FROM Users u
会返回多少个对象?我认为你需要使用'DISTINCT'。即SELECT distinct u FROM Users u LEFT JOIN FETCH u.projects proj ...
.
这就是为什么规范部分处理“带有关系的查询”使用带有 DISTINCT 关键字的示例。集合上的连接为集合中的每个元素返回一行,并且 JPA 的结果反映了您请求的 SQL 结果,即使结果可能未明确包含在选择中。
非常感谢! 'DISTINCT' 确实是解决方案!
@Priyesh 由于您的解决方案适用于 Rooky,您应该发布您的解决方案作为答案。所以,Rooky 可以接受。
【参考方案1】:
如果你使用 SELECT u FROM Users u 会返回多少个对象?我认为你需要使用'DISTINCT'。即
SELECT distinct u FROM Users u LEFT JOIN FETCH u.projects proj ...
【讨论】:
以上是关于JPQL JOIN FETCH 多个表也带有空集合的主要内容,如果未能解决你的问题,请参考以下文章
带有 ON 子句或替代方法的休眠 LEFT JOIN FETCH