第一次获取连接然后简单连接时,Hibernate不会生成JOIN

时间:2018-04-06 16:11:30

标签: java mysql hibernate jpa join

鉴于以下实体:

@Entity
public class User {

  @Id
  private Long id;

  private String name;

  @OneToMany(mappedBy = "user", fetch = LAZY)
  private Set<UserRole> userRoles = new HashSet<>();

}

@Entity
public class UserRole {

  @Id
  private Long id;

  private String name;

  @ManyToOne(fetch = LAZY)
  private User user;

  @ManyToMany(fetch = LAZY)
  private Set<Article> articles = new HashSet<>();

}

@Entity
public class Article {

  @Id
  private Long id;

  private String name;

  @ManyToMany(mappedBy = "articles", fetch = LAZY)
  private Set<UserRole> userRoles = new HashSet<>();

}

我正构建以下查询:

From<?, ?> root = query.from(User.class);
From<?, ?> joinedUserRoles = (From<?, ?>) root.fetch("userRoles", JoinType.INNER);
From<?, ?> joinedArticles = joinedUserRoles.join("articles", JoinType.INNER);
query.where(joinedArticles.in(someArticles));

我们的想法是在简单加入User#userRoles时获取加入UserRole#articles。问题是生成的查询无效:

select
    user0_.id as id1_6_0_,
    userroles1_.id as id1_7_1_,
    user0_.name as name5_6_0_,
    userroles1_.role as role2_7_1_,
    userroles1_.user_id as User_i3_7_1_,
    userroles1_.user_id as User_i3_7_0__,
    userroles1_.id as id1_7_0__ 
from
    User user0_ 
inner join
    UserRole userroles1_ 
        on user0_.id=userroles1_.user_id 
where
    generatedAlias2 in (
        ?
    )

抛出错误:

SQLSyntaxErrorException: Unknown column 'generatedAlias2' in 'where clause'

实际上,由于某种原因,JPA / Hibernate没有生成简单连接UserRole#articles

知道发生了什么?

我在使用Hibernate 5.2.16。

2 个答案:

答案 0 :(得分:2)

根据Batch fetching - optimizing object graph loading

  

JPQL不允许连接提取的别名,因此如果您还要查询关系,则必须连接两次。

为什么禁止这样做的一个例子是in this answer

您的转换允许构建条件对象,但提供商似乎没有正确理解它并且无法解析articles别名。

使用fetch()替换join()在加载延迟关系方面可能并不理想,但应构建有效的查询。

答案 1 :(得分:0)

再看一遍:这有什么问题?似乎工作。

CriteriaQuery<User> cq = cb.createQuery(User.class);
Root<User> user = cq.from(User.class);
Join<User, UserRole> userRoles = user.join("userRoles", JoinType.INNER);
Join<UserRole, Article> articles = userRoles.join("articles", JoinType.INNER);
cq.where(articles.in(Arrays.asList(new Long[]{1L})));