Hibernate 在第一次 fetch-joining 然后 simple-joining 时不生成 JOIN

Posted

技术标签:

【中文标题】Hibernate 在第一次 fetch-joining 然后 simple-joining 时不生成 JOIN【英文标题】:JOIN not generated by Hibernate when first fetch-joining then simple-joining 【发布时间】:2018-09-16 17:29:20 【问题描述】:

给定以下实体:

@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));

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

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。

【问题讨论】:

不清楚你的目标是什么。什么是用户角色?是不是类似于“OriginalPoster”和“Responder”?如果是这样,您为什么在那里有文章列表?为什么在 User 类中没有文章列表?此外,为什么要在文章中列出用户角色?可以有多少个 UserRole?如前所述,如果只有两个,那么在此处列出该列表是没有意义的。你真的需要明确你的目标。 @KarlNicholas 感谢您的评论。实体已经过彻底设计,所有这些关系都是我们模型所需的。我真的不知道我可以提供什么额外的细节。基本上,问题是:如何在获取加入后进行简单加入。我不确定这里还需要什么。 对,那么UserRole的作用是什么? 【参考方案1】:

根据Batch fetching - optimizing object graph loading:

JPQL 不允许 join fetch 的别名,因此如果您还想查询关系,则必须加入两次。

in this answer 给出了禁止这样做的示例。

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

fetch() 替换为join() 在加载惰性关系方面可能并不理想,但应该构造一个有效的查询。

【讨论】:

有趣的链接,谢谢!我不知道 fetch-joins 不能使用别名。我明天再试一次,我会回来找你的。【参考方案2】:

又看了一遍:这有什么问题?似乎有效。

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)));

【讨论】:

以上是关于Hibernate 在第一次 fetch-joining 然后 simple-joining 时不生成 JOIN的主要内容,如果未能解决你的问题,请参考以下文章

使用hibernate 5如何在第一次执行时创建一个带有ROW的表?

hibernate缓存技术

Hibernate ORM框架——续第一章:Hibernate的增删改查(第一个hibernate代码的优化)

hibernate 第一天

MyBatis第一章

hibernate——第一次简单的使用