我也有完全一样的问题。经过几个小时的处理这个问题,调试 Hibernate 源代码,并一遍又一遍地检查书籍和 JPA 2.0 规范中的示例后,我决定在 EclipseLink 中尝试一下。
因此,我创建了一个非常简单的示例:一名员工拥有电话号码地图,其中键是电话类型(家庭、办公室、手机),值是电话号码。
@ElementCollection(fetch=FetchType.EAGER)
@CollectionTable(name="emp_phone")
@MapKeyColumn(name="phone_type")
@Column(name="phone_num")
private Map<String, String> phoneNumbers;
我可以验证这是否与 EclipseLink 2.1 和 OpenJPA 2.1.0 完美配合,但在 Hibernate 3.5.3、3.6.1.、3.6.3 中失败
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Employee> criteria = builder.createQuery(Employee.class);
Root<Employee> employeeRoot = criteria.from(Employee.class);
criteria.select(employeeRoot);
MapJoin<Employee, String, String> phoneRoot = employeeRoot.joinMap("phoneNumbers");
criteria.where(builder.equal(phoneRoot.key(), "HOME"));
System.out.println(entityManager.createQuery(criteria).getResultList());
我想,如果 Criteria API 失败,也许我可以使用命名查询来完成。有趣的是,Hibernate 不支持 KEY、VALUE 或 ENTRY 关键字,因此查询被证明是格式错误的。
http://opensource.atlassian.com/projects/hibernate/browse/HHH-5396
这是运行的:
String query = "SELECT e FROM Employee e JOIN e.phoneNumbers p WHERE KEY(p) IN ('HOME')";
System.out.println(entityManager.createQuery(query, Employee.class).getResultList());
在 hibernate 中它会生成以下 SQL 查询:
select
employee0_.id as id0_,
employee0_.name as name0_
from
Employee employee0_
inner join
emp_phone phonenumbe1_
on employee0_.id=phonenumbe1_.Employee_id
where
KEY(phonenumbe1_.phone_num) in (
'HOME'
)
这显然是畸形的。
同样,在 EclipseLink 和 OpenJPA 中,这是可行的。
因此,显然 Hibernate 一定出了问题。我已在 Hibernate Jira 问题跟踪器中提交了一个错误
https://hibernate.atlassian.net/browse/HHH-6103
并已在 Hibernate 用户论坛中发布了该问题
最后,我必须使用包含与地图相同条目的可嵌入对象集合来解决问题。我被迫在可嵌入中实现 equals 和 hasHCode 以满足相同的行为。