Spring Data 'Left Join Fetch' 查询返回 null

Posted

技术标签:

【中文标题】Spring Data \'Left Join Fetch\' 查询返回 null【英文标题】:Spring Data 'Left Join Fetch' query returning nullSpring Data 'Left Join Fetch' 查询返回 null 【发布时间】:2015-01-30 01:06:53 【问题描述】:

我的查询如下所示:

@Query("SELECT p FROM Pilot p LEFT JOIN FETCH p.playerShips WHERE p.nickname = (:nickname)")

到目前为止一切顺利。即使 playerShips 为空,我也会获得 Pilot 实例。 现在,我想只获取不活跃的船只,所以我修改了我的查询,如下所示:

@Query("SELECT p FROM Pilot p LEFT JOIN FETCH p.playerShips s WHERE p.nickname = (:nickname) AND s.active = false")

而且我作为一名飞行员得到了空值,所以它显然不起作用。 如果有人能解释我如何使用适用于子元素的 WHERE 子句创建 JOIN FETCH 查询,我会很高兴。提前致谢。

【问题讨论】:

你的表结构是什么 playerShips 表包含布尔值的“活动”列和引用 Pilot.ID 的外键列“pilot_id”,这很重要。 选择性地仅检索 ~ToMany 关系的一部分不是一个好主意。你将面临很多问题。而是在代码中进行过滤。除非您想完全忽略整个应用程序中的所有非活动船舶(这就是您的答案所做的)。 您能否详细说明您的评论?现在有了我的回答,我正在调用 findByNicknameFetchInactiveShips,它只获取不活动的船只,因此它们根本不会被忽略。此外,仅检索部分 ToMany 可能会导致什么问题?此外,当我使用纯 jpql 时出现错误“with-clause not allowed on fetched associates; use filters”,所以我现在正在做的“使用过滤器”一定是有原因的。我总是有改进的空间,所以我想听听更多关于它的信息。感谢您的评论。 【参考方案1】:

只需将其移至连接条件即可:

@Query("SELECT p FROM Pilot p LEFT JOIN FETCH p.playerShips s ON s.active = false WHERE p.nickname = (:nickname)")

ON 子句在 JPA 2.1 中定义

【讨论】:

试过了。抛出以下错误:with-clause not allowed on fetched associations;使用过滤器。我现在正在寻找过滤器,但我认为不能将它们与 Spring Data JPA 一起使用。 试试这个或原生查询:SELECT p FROM Pilot p LEFT JOIN FETCH p.playerShips s WHERE p.nickname = (:nickname) AND (s is null OR s.active = false)【参考方案2】:

经过大量研究,我决定实现一个自定义存储库,以便我可以使用 Hibernate 过滤器,现在它可以工作了。

PilotRepository:

@Repository
public interface PilotRepository extends JpaRepository<Pilot, Long>, PilotRepositoryCustom
/*spring data methods here*/

PilotRepositoryCustom:

public interface PilotRepositoryCustom 
    public Pilot findByNicknameFetchInactiveShips(String nickname);

PilotRepositoryImpl:

public class PilotRepositoryImpl implements PilotRepositoryCustom

    @PersistenceContext
    EntityManager entityManager;

    @Override
    public Pilot findByNicknameFetchInactiveShips(String nickname) 
        Session session = entityManager.unwrap(Session.class);
        session.enableFilter("active").setParameter("active", false);
        Query query = entityManager.createQuery(
                "SELECT p FROM Pilot p " +
                "LEFT JOIN FETCH p.playerShips ps " +
                "LEFT JOIN FETCH ps.ship s " +
                "WHERE p.nickname = (:nickname)");
        query.setParameter("nickname", nickname);
        return (Pilot)query.getSingleResult();
    

关于春季数据就是这样。现在过滤器配置:Pilot Entity:

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "pilot")
    @Filter(name="active", condition = "active = :active")
    private List<PlayerShip> playerShips;

PlayerShip 实体:

@Entity
@Table(name="player_ship")
@FilterDef(name="active", parameters=@ParamDef(name="active",type="java.lang.Boolean"))
public class PlayerShip 
    /*...*/
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "pilot_id")
    private Pilot pilot;
    /*...*/

重要提示: 如果您在 @ParamDef 中使用布尔值,请确保键入 java.lang.Boolean 而不仅仅是 Boolean。我花了一个多小时想知道为什么我不断收到 parameter not found/not defined 错误

【讨论】:

以上是关于Spring Data 'Left Join Fetch' 查询返回 null的主要内容,如果未能解决你的问题,请参考以下文章

LEFT JOIN FETCH 不起作用 - Spring 数据 JPA

R语言进行dataframe数据左连接(Left join):使用R原生方法data.tabledplyr等方案

高效的 left_join 和后续合并

使用by = c(x = y)错误在函数内执行dplyr :: left_join

Spring Data Join 规范

left_join 两个数据帧并覆盖