我有一个问题,子查询和JPA花了我很多时间,我找不到一个直接的解决方案,所以我用了两个不同的查询来解决它。
使用Spring和JPA,我有两个类似的实体:
public Class Entity{
@Id
private Long id;
@OneToMany(mappedBy = "entity", fetch = FetchType.LAZY)
private Set<SecondEntity> secondEntities;
}
public class SecondEntity{
@Id
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn
private Entity entityId;
@Column
private Integer number;
}
我想使用JPA和规范来运行这样的查询:
SELECT *
FROM Entity
WHERE id IN (SELECT id FROM Entity LEFT JOIN SecondEntity ON Entity.id = SecondEntity.entityId WHERE number = ?)
请不要关注其他解决方法,而是帮助我理解我们是否可以让Hibernate做我想做的事情。
出现问题是因为像这样初始化subroot
:
Subquery<Entity> subquery = query.subquery(Entity.class);
Root<Entity> subroot = subquery.from(Entity.class);
from()方法使Hibernate向查询添加一个crossJoin,它看起来像这样:
SELECT *
FROM Entity
WHERE id IN (SELECT id FROM Entity LEFT OUTER JOIN SecondEntity ON Entity.id = SecondEntity.entityId CROSS JOIN Employee WHERE crossjoincondition AND number = ?)
有人知道如何初始化子查询与另一种方法,以避免交叉连接?我知道其他实现,比如做一个不同的查询和混合的结果,或者写一个@Query专用可以更好地工作,但我只是想知道如何管理这为将来的目的?
我能找到的唯一解决方案是建议删除@JoinColumn
注释和mappedBy属性,但我不能修改这个映射,因为我需要它用于另一个方法。
有一个简单的方法,
你可以像下面这样在规范中使用连接。
在我的代码中,我使用了INNER连接,你可以使用你自己的连接类型
public static Specification<Post> byTagNames(String[] tagNames) {
return (root, query, criteriaBuilder) -> {
if (tagNames == null || tagNames.length > 0) {
return criteriaBuilder.conjunction();
}
Join<Post, Tag> postTagsTable = root.join("tags", JoinType.INNER);
return postTagsTable.<String>get("name").in(tagNames);
};
}
我希望这对你有帮助!