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等方案