java JPA 2 和 Hibernate 3.5.1 成员查询不起作用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2687690/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JPA 2 and Hibernate 3.5.1 MEMBER OF query doesnt work
提问by Ed_Zero
I'm trying the following JPQL and it fails misserably:
我正在尝试以下 JPQL,但它失败了:
Query query = em.createQuery("SELECT u FROM User u WHERE 'admin' MEMBER OF u.roles");
List users = query.query.getResultList();
I get the following exception:
我收到以下异常:
ERROR [main] PARSER.error(454) | <AST>:0:0: unexpected end of subtree
java.lang.IllegalArgumentException: org.hibernate.hql.ast.QuerySyntaxException: unexpected end of subtree [SELECT u FROM com.online.data.User u WHERE 'admin' MEMBER OF u.roles] ERROR [main] PARSER.error(454) | <AST>:0:0: expecting "from", found '<ASTNULL>'
...
...
Caused by: org.hibernate.hql.ast.QuerySyntaxException: unexpected end of subtree [SELECT u FROM com.online.data.User u WHERE 'admin' MEMBER OF u.roles]
I have Spring 3.0.1.RELEASE, Hibernate 3.5.1-Final and maven to glue dependencies.
我有 Spring 3.0.1.RELEASE、Hibernate 3.5.1-Final 和 maven 来粘合依赖项。
User class:
用户类:
@Entity
public class User {
@Id
@Column(name = "USER_ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column(unique = true, nullable = false)
private String username;
private boolean enabled;
@ElementCollection
private Set<String> roles = new HashSet<String>();
...
}
Spring configuration:
弹簧配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/tx/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- Reading annotation driven configuration -->
<tx:annotation-driven transaction-manager="transactionManager" />
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="maxActive" value="100" />
<property name="maxWait" value="1000" />
<property name="poolPreparedStatements" value="true" />
<property name="defaultAutoCommit" value="true" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="databasePlatform" value="${hibernate.dialect}" />
</bean>
</property>
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.current_session_context_class">thread</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.NoCacheProvider</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.show_comments">true</prop>
</props>
</property>
<property name="persistenceUnitName" value="punit" />
</bean>
<bean id="JpaTemplate" class="org.springframework.orm.jpa.JpaTemplate">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
</beans>
Persistence.xml
持久化文件
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="punit" transaction-type="RESOURCE_LOCAL" />
</persistence>
pom.xml maven dependencies.
pom.xml Maven 依赖项。
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>${hibernate.version}</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.2.2</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-acl</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>jsr250-api</artifactId>
<version>1.0</version>
</dependency>
<properties>
<!-- Application settings -->
<spring.version>3.0.1.RELEASE</spring.version>
<hibernate.version>3.5.1-Final</hibernate.version>
Im running a unit test to check the configuration and I am able to run other JPQL queries the only ones that I am unable to run are the IS EMPTY, MEMBER OF conditions.
我正在运行单元测试来检查配置,并且我能够运行其他 JPQL 查询,我唯一无法运行的是 IS EMPTY、MEMBER OF 条件。
The complete unit test is as follows:
完整的单元测试如下:
TestIntegration
测试集成
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/spring/dataLayer.xml"})
@Transactional
@TransactionConfiguration
public class TestUserDaoImplIntegration {
@PersistenceContext
private EntityManager em;
@Test
public void shouldTest() throws Exception {
try {
//WORKS
Query query = em.createQuery("SELECT u FROM User u WHERE 'admin' in elements(u.roles)");
List users = query.query.getResultList();
} catch (Exception e) {
e.printStackTrace();
throw e;
}
try {
//DOES NOT WORK
Query query = em.createQuery("SELECT u FROM User u WHERE 'admin' MEMBER OF u.roles");
List users = query.query.getResultList();
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
}
回答by Pascal Thivent
Your query looks perfectly fineto me. For the record, this is what the JPA 2.0 specification writes about the MEMBER OFoperator:
您的查询对我来说非常好。作为记录,这是 JPA 2.0 规范关于MEMBER OF操作符的内容:
4.6.13 Collection Member Expressions
The syntax for the use of the comparison operator
MEMBER OFin an collection_member_expression is as follows:collection_member_expression ::= entity_or_value_expression [NOT] MEMBER [OF] collection_valued_path_expression entity_or_value_expression ::= single_valued_object_path_expression | state_field_path_expression | simple_entity_or_value_expression simple_entity_or_value_expression ::= identification_variable | input_parameter | literalThis expression tests whether the designated value is a member of the collection specified by the collection-valued path expression.
Expressions that evaluate to embeddable types are not supported in collection member expressions. Support for use of embeddables in collection member expressions may be added in a future release of this specification.
If the collection valued path expression designates an empty collection, the value of the
MEMBEROF expression isFALSEand the value of theNOT MEMBER OFexpression isTRUE. Otherwise, if the value of the collection_valued_path_expression or entity_or_value_expression in the collection member expression is NULL or unknown, the value of the collection member expression is unknown.Example:
SELECT p FROM Person p WHERE 'Joe' MEMBER OF p.nicknames
4.6.13 集合成员表达式
MEMBER OF在 collection_member_expression 中使用比较运算符的语法如下:collection_member_expression ::= entity_or_value_expression [NOT] MEMBER [OF] collection_valued_path_expression entity_or_value_expression ::= single_valued_object_path_expression | state_field_path_expression | simple_entity_or_value_expression simple_entity_or_value_expression ::= identification_variable | input_parameter | literal此表达式测试指定的值是否是由集合值路径表达式指定的集合的成员。
集合成员表达式不支持计算为可嵌入类型的表达式。在本规范的未来版本中可能会添加对在集合成员表达式中使用可嵌入项的支持。
如果集合值路径表达式指定一个空集合,则
MEMBEROF 表达式FALSE的值为 ,NOT MEMBER OF表达式的值为TRUE。否则,如果集合成员表达式中的collection_valued_path_expression 或entity_or_value_expression 的值为NULL 或未知,则集合成员表达式的值未知。例子:
SELECT p FROM Person p WHERE 'Joe' MEMBER OF p.nicknames
So, because I can't see anything wrong in your query, I've tested your code with EclipseLink1and the following snippet just works:
因此,因为我在您的查询中看不出任何错误,所以我已经使用 EclipseLink 1测试了您的代码,并且以下代码段有效:
Query query = em.createQuery("SELECT u FROM User u WHERE 'admin' MEMBER OF u.roles");
List list = query.getResultList();
But fails indeed with Hibernate EntityManager 3.5.1-Final. This sounds like a bug, feel free to raise a Jira issue.
但是使用 Hibernate EntityManager 3.5.1-Final 确实失败了。这听起来像是一个错误,请随时提出Jira 问题。
1Just in case, I used the following Maven profile (for the JPA provider):
1以防万一,我使用了以下 Maven 配置文件(用于 JPA 提供程序):
<profile>
<id>eclipselink</id>
<repositories>
<repository>
<id>eclipselink</id>
<url>http://www.eclipse.org/downloads/download.php?r=1&nf=1&file=/rt/eclipselink/maven.repo/</url>
</repository>
</repositories>
<dependencies>
<!-- See http://wiki.eclipse.org/EclipseLink/Maven -->
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<version>2.0.0</version>
</dependency>
<!-- optional - only needed if you are using JPA outside of a Java EE container-->
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>javax.persistence</artifactId>
<version>2.0.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</profile>
And this is my persistence.xml:
这是我的persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="TestPu" transaction-type="RESOURCE_LOCAL">
<class>com.stackoverflow.q2688144.User</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:derby:testdb;create=true"/>
<property name="eclipselink.target-database" value="DERBY"/>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
</properties>
</persistence-unit>
</persistence>
Update:reported in HHH-5209
更新:在HHH-5209 中报告
回答by peterbrown
Hibernate Bug #HHH-5209, as workaround use the following syntax:
Hibernate Bug #HHH-5209,作为解决方法使用以下语法:
select user from User user where :role in elements(user.roles)
回答by bvarner
Your query is absolutely correct and should work. I ran into this same problem just today, and thanks to this post, was able to stop banging my head against the wall.
您的查询是绝对正确的,应该可以工作。就在今天,我遇到了同样的问题,多亏了这篇文章,我才不再用头撞墙。
Since @ElementCollection is really a nice shortcut to a joined element with an intrinsic association, you can still use join semantics in your query.
由于@ElementCollection 确实是具有内在关联的连接元素的一个很好的快捷方式,因此您仍然可以在查询中使用连接语义。
To put that in better terms, you need to join your collection, and set a condition in the where.
更确切地说,您需要加入您的收藏,并在 where 中设置条件。
To put that into something more concrete...
把它变成更具体的东西......
Your query:
您的查询:
SELECT u FROM User u WHERE 'admin' MEMBER OF u.roles
Can be written as:
可以写成:
SELECT u FROM User u JOIN u.roles r WHERE r = 'admin'
Hope this helps!
希望这可以帮助!
回答by Behrang Saeedzadeh
I think member ofcannot be used with a @ElementCollectionproperty.
我认为member of不能与@ElementCollection属性一起使用。

