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 多个表也带有空集合的主要内容,如果未能解决你的问题,请参考以下文章

JPQL 查询:属于多个类别的项目

如何过滤 JPA/JPQL 中的集合?

带有 ON 子句或替代方法的休眠 LEFT JOIN FETCH

带有分页的 Spring-Data FETCH JOIN 不起作用

使用 JPQL 从实体的元素集合中删除

是否可以在Doctrine中组合fetch join和COUNT?