我有以下条件构建器查询
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Object> critQuery = cb.createQuery();
Root<Role> role = critQuery.from(Role.class);
//create a join between role and permission
MapJoin<Role,String,Permission> perm = role.joinMap("permissions");
critQuery.multiselect(role.get("label"), perm.key(), perm.value());
//this line throws NPE
Query query = em.createQuery(critQuery);
最后一行抛出空指针异常。
java.lang.NullPointerException
at org.hibernate.ejb.criteria.path.AbstractPathImpl.prepareAlias(AbstractPathImpl.java:246)
at org.hibernate.ejb.criteria.path.AbstractPathImpl.render(AbstractPathImpl.java:253)
at org.hibernate.ejb.criteria.path.AbstractPathImpl.renderProjection(AbstractPathImpl.java:261)
答案 0 :(得分:9)
我有完全相同的问题。经过几个小时的处理,以及调试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 Issue Tracker中提交了一个错误
http://opensource.atlassian.com/projects/hibernate/browse/HHH-6103
已在Hibernate用户论坛中发布了该问题
答案 1 :(得分:2)
对于那些坚持使用Hibernate 3.6的人,我能够通过地图加入并使用谓词限制结果。这个解决方案有一个重要的警告。只有当您感兴趣的地图密钥存在于每条记录时,此技术才有效。如果没有,您将丢失结果集中可能会出现的记录。
我的情况与埃德温的例子非常相似。我们有一个Person实体,其中包含当前名称的映射,其中map键是名称类型,值是Name对象。就我而言,我想要检索一个人当前的标准名称。
Root<Person> person = query.from(Person.class);
Join currentName = person.join("currentNames");
NameLookup standardName = NameLookup.lookup("ST");
Predicate useridMatches = criteria.equal(person.get("userid"), "user1");
Predicate isStandardName = criteria.equal(currentName.get("nameType"), standardName);
Predicate useridAndStandardName = criteria.and(useridMatches, isStandardName);
query.where(useridAndStandardName);
在JPQL中,我们通常使用WITH子句来限制连接。
inner join person.currentNames currentStandardName
with currentStandardName.nameType.id = :standardNameLookupId