我正在使用Hibernate来实现一个Search页面,其中可能会或可能不会使用不同的标准。一个标准是ID
中的SpecialTable
。另一个标准是"Or"
或MainTable
中的SpecialTable
。一切都是可选的。
假设我同时提供标准#1和#2。在这种情况下,我想分别加入SpecialTable
两次,使用不同的别名,因为这些标准并不相互依赖。
// Optional Criterion #1
if (searchCriteria.getSpecialId() != null) {
criteriaQuery.createAlias("specialTable", "specialTableJoin1", JoinType.INNER_JOIN);
criteriaQuery.add(Restrictions.eq("specialTableJoin1.id", searchCriteria.getSpecialId()));
}
// ...
// Optional Criterion #2
if (!StringUtils.isBlank(searchCriteria.getRequestPublicationTitle())) {
criteriaQuery.createAlias("specialTable", "specialTableJoin2", JoinType.LEFT_OUTER_JOIN);
String titleForQuery = "%" + searchCriteria.getRequestPublicationTitle().replaceAll("^.*,", "").trim() + "%";
Disjunction requestOrPublicationTitle = Restrictions.disjunction();
requestOrPublicationTitle.add(Restrictions.ilike("title", titleForQuery));
requestOrPublicationTitle.add(Restrictions.ilike("specialTableJoin2.publicationTitle", titleForQuery));
错误:
org.hibernate.QueryException: duplicate association path: specialTable
有解决方案吗我的别名是不同的,但它仍然不起作用。
这是一个古老的Hibernate bug - https://hibernate.atlassian.net/browse/HHH-879 - 自2005年以来仍然开放!
唯一的解决方案是预先定义所有别名,而不是每个使用的标准。但如果在别名创建中使用不同的JoinType(INNER与LEFT_OUTER_JOIN),则可能会出现问题。如果它是全部相同的JoinType,那么你已经设置好了。
我使用的解决方法是定义一个公共LEFT_OUTER_JOIN,其中需要INNER / LEFT_OUTER_JOIN。左连接仍然适用于Criterion#1,因为它受Value = ...的约束,因此与原始Inner Join没有实际区别。
// Prepare aliases (joins)
// -----------------------
if (searchCriteria.getSpecialId() != null || !StringUtils.isBlank(searchCriteria.getTitle())) {
// Note: LEFT JOIN for both Special ID and Title,
// since Hibernate Criteria API only allows 1 alias & join per Table (https://hibernate.atlassian.net/browse/HHH-879), and the 2nd criterion requires a Left Outer Join
criteriaQuery.createAlias("specialTable", "st", JoinType.LEFT_OUTER_JOIN);
}
// ... All other aliases prepared ...
// Actual Criteria
// ... use the "st" single alias