Hibernate many-to-many data retrieval, via query

2020-04-18 08:02发布

问题:

Please help me, I think there is something that I am not doing correct. I have User and Contact, that are in Many-to-Many relation.

User.java:

public class User {

    private Integer userID;

    private String userLoginEmail;

    private Set<Contact> contactSet = new HashSet<Contact>();

    public User() {

    }

    .
    getters and setters
    .

Contact.java

public class Contact implements Serializable {
    private Integer contactID;
    private Set<User> userSet= new HashSet<User>();
    public Contact() {
    }
    .
    getters and setters
    .
    .

Mapping for User:

<hibernate-mapping package="com.smallworks.model" schema="projectdb">
 <class name="User" table="USERACCOUNT">
  <id column="USER_ID" length="500" name="userID">
   <generator class="increment"/>
  </id>
  <set cascade="all" fetch="select" lazy="true" name="contactSet"
   sort="unsorted" table="USER_CONTACT">
   <key column="USER_ID"/>
   <many-to-many class="com.smallworks.model.Contact"
    column="CONTACT_ID" order-by="CONTACT_ID" unique="false"/>
  </set>
  </class>
</hibernate-mapping>

Mapping for Contact:

<hibernate-mapping package="com.smallworks.model" schema="projectdb">
 <class name="Contact" table="CONTACT">
  <id column="CONTACT_ID" length="500" name="contactID">
   <generator class="increment"/>
  </id>
  <!-- many to many mapping with the User via User_Contact table -->
  <set inverse="true" lazy="false" name="userSet" sort="unsorted" table="USER_CONTACT">
    <key column="USER_ID"/>
    <many-to-many class="com.smallworks.model.Contact" column="CONTACT_ID" unique="false"/>
  </set>
 </class>
</hibernate-mapping>

I am trying to write a query to get the Contacts associated with the User that is logged in.

When I try to write the following query:

Query query=session.createQuery("select contact from com.src.model.Contact  contact join contact.userSet u where u.userID=:userID");
        query.setParameter("userID", user.getUserID());
        contactList=query.list();

I get the following error:

org.hibernate.QueryException: could not resolve property: userID of: com.src.model.Contact [select contact from com.src.model.Contact  contact join contact.userSet u where u.userID=:userID]

I know what the error message means, but I am not being able to figure out how to write this query.

First I did like this: Hibernate many-to-many data retrieval

but now I am writing a query because I need to check on the Contact status, and other parameters.

Thanks Harbir

This is how I am calling the query:

@Override
    public List<Contact> getContactList(User user) {
        log.info("getContactList(User user)");
        List contactList = new ArrayList();
        Session session = sessionFactory.getCurrentSession();
        System.out.println("About to hit the query");
        Query query=session.createQuery("select contact from com.smallworks.model.Contact  contact join contact.userSet u where u.userID=:userID");
        query.setParameter("userID", user.getUserID());
        contactList=query.list();
        return contactList;
    }

The following is the stack trace:

About to hit the query
18:56:01.011 [http-bio-8080-exec-6] DEBUG o.h.hql.ast.QueryTranslatorImpl - parse() - HQL: select contact from com.smallworks.model.Contact  contact join contact.userSet u where u.userID=:userID
18:56:01.020 [http-bio-8080-exec-6] DEBUG org.hibernate.hql.ast.AST - --- HQL AST ---
 \-[QUERY] 'query'
    +-[SELECT_FROM] 'SELECT_FROM'
    |  +-[FROM] 'from'
    |  |  +-[RANGE] 'RANGE'
    |  |  |  +-[DOT] '.'
    |  |  |  |  +-[DOT] '.'
    |  |  |  |  |  +-[DOT] '.'
    |  |  |  |  |  |  +-[IDENT] 'com'
    |  |  |  |  |  |  \-[IDENT] 'smallworks'
    |  |  |  |  |  \-[IDENT] 'model'
    |  |  |  |  \-[IDENT] 'Contact'
    |  |  |  \-[ALIAS] 'contact'
    |  |  \-[JOIN] 'join'
    |  |     +-[DOT] '.'
    |  |     |  +-[IDENT] 'contact'
    |  |     |  \-[IDENT] 'userSet'
    |  |     \-[ALIAS] 'u'
    |  \-[SELECT] 'select'
    |     \-[IDENT] 'contact'
    \-[WHERE] 'where'
       \-[EQ] '='
          +-[DOT] '.'
          |  +-[IDENT] 'u'
          |  \-[IDENT] 'userID'
          \-[COLON] ':'
             \-[IDENT] 'userID'

18:56:01.020 [http-bio-8080-exec-6] DEBUG org.hibernate.hql.ast.ErrorCounter - throwQueryException() : no errors
18:56:01.041 [http-bio-8080-exec-6] DEBUG o.h.hql.antlr.HqlSqlBaseWalker - select << begin [level=1, statement=select]
18:56:01.050 [http-bio-8080-exec-6] DEBUG o.hibernate.hql.ast.tree.FromElement - FromClause{level=1} :  com.smallworks.model.Contact (contact) -> contact0_
18:56:01.051 [http-bio-8080-exec-6] DEBUG o.h.hql.ast.tree.FromReferenceNode - Resolved :  contact -> contact0_.CONTACT_ID
18:56:01.053 [http-bio-8080-exec-6] DEBUG org.hibernate.hql.ast.tree.DotNode - getDataType() : userSet -> org.hibernate.type.SetType(com.smallworks.model.Contact.userSet)
18:56:01.053 [http-bio-8080-exec-6] DEBUG o.h.hql.ast.tree.FromElementFactory - createManyToMany() : path = contact.userSet role = com.smallworks.model.Contact.userSet associatedEntityName = com.smallworks.model.Contact
18:56:01.055 [http-bio-8080-exec-6] DEBUG o.hibernate.hql.ast.tree.FromElement - FromClause{level=1} :  com.smallworks.model.Contact (u) -> contact2_
18:56:01.055 [http-bio-8080-exec-6] DEBUG o.hibernate.hql.ast.tree.FromClause - addJoinByPathMap() : contact.userSet -> smallworksdb.CONTACT contact2_
18:56:01.055 [http-bio-8080-exec-6] DEBUG org.hibernate.hql.ast.tree.DotNode - dereferenceCollection() : Created new FROM element for contact.userSet : smallworksdb.USER_CONTACT contact2_
18:56:01.055 [http-bio-8080-exec-6] DEBUG o.h.hql.ast.tree.FromReferenceNode - Resolved :  contact.userSet -> .
18:56:01.056 [http-bio-8080-exec-6] DEBUG org.hibernate.hql.ast.HqlSqlWalker - createFromJoinElement() : -- join tree --
 \-[JOIN_FRAGMENT] FromElement: 'smallworksdb.USER_CONTACT contact2_' FromElement{explicit,not a collection join,not a fetch join,fetch non-lazy properties,classAlias=u,role=com.smallworks.model.Contact.userSet,tableName=smallworksdb.CONTACT,tableAlias=contact2_,origin=smallworksdb.CONTACT contact0_,colums={contact0_.CONTACT_ID ,className=com.smallworks.model.Contact}}

18:56:01.056 [http-bio-8080-exec-6] DEBUG o.h.hql.ast.tree.FromReferenceNode - Resolved :  contact -> contact0_.CONTACT_ID
18:56:01.060 [http-bio-8080-exec-6] DEBUG o.h.hql.ast.tree.FromReferenceNode - Resolved :  u -> contact2_.CONTACT_ID
18:56:01.060 [http-bio-8080-exec-6] DEBUG o.s.w.s.m.a.AnnotationMethodHandlerExceptionResolver - Resolving exception from handler [com.smallworks.controller.ProjectController@1f183871]: org.hibernate.QueryException: could not resolve property: userID of: com.smallworks.model.Contact [select contact from com.smallworks.model.Contact  contact join contact.userSet u where u.userID=:userID]
18:56:01.062 [http-bio-8080-exec-6] DEBUG o.s.w.s.m.a.ResponseStatusExceptionResolver - Resolving exception from handler [com.smallworks.controller.ProjectController@1f183871]: org.hibernate.QueryException: could not resolve property: userID of: com.smallworks.model.Contact [select contact from com.smallworks.model.Contact  contact join contact.userSet u where u.userID=:userID]
18:56:01.062 [http-bio-8080-exec-6] DEBUG o.s.w.s.m.s.DefaultHandlerExceptionResolver - Resolving exception from handler [com.smallworks.controller.ProjectController@1f183871]: org.hibernate.QueryException: could not resolve property: userID of: com.smallworks.model.Contact [select contact from com.smallworks.model.Contact  contact join contact.userSet u where u.userID=:userID]
18:56:01.069 [http-bio-8080-exec-6] DEBUG o.s.web.servlet.DispatcherServlet - Could not complete request
org.hibernate.QueryException: could not resolve property: userID of: com.smallworks.model.Contact [select contact from com.smallworks.model.Contact  contact join contact.userSet u where u.userID=:userID]
    at org.hibernate.persister.entity.AbstractPropertyMapping.propertyException(AbstractPropertyMapping.java:67) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.persister.entity.AbstractPropertyMapping.toType(AbstractPropertyMapping.java:61) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.persister.entity.AbstractEntityPersister.toType(AbstractEntityPersister.java:1385) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.persister.collection.AbstractCollectionPersister.toType(AbstractCollectionPersister.java:1457) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.hql.ast.tree.FromElementType.getPropertyType(FromElementType.java:302) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.hql.ast.tree.FromElement.getPropertyType(FromElement.java:407) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.hql.ast.tree.DotNode.getDataType(DotNode.java:589) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.hql.ast.tree.DotNode.prepareLhs(DotNode.java:264) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.hql.ast.tree.DotNode.resolve(DotNode.java:211) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.hql.ast.tree.FromReferenceNode.resolve(FromReferenceNode.java:117) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.hql.ast.tree.FromReferenceNode.resolve(FromReferenceNode.java:113) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.hql.ast.HqlSqlWalker.resolve(HqlSqlWalker.java:750) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.hql.antlr.HqlSqlBaseWalker.expr(HqlSqlBaseWalker.java:1216) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.hql.antlr.HqlSqlBaseWalker.exprOrSubquery(HqlSqlBaseWalker.java:4041) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.hql.antlr.HqlSqlBaseWalker.comparisonExpr(HqlSqlBaseWalker.java:3525) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.hql.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:1762) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.hql.antlr.HqlSqlBaseWalker.whereClause(HqlSqlBaseWalker.java:776) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.hql.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:577) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.hql.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:281) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.hql.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:229) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.hql.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:251) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.hql.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:183) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.hql.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:134) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:101) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:80) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.engine.query.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:94) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.impl.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:156) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.impl.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:135) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at org.hibernate.impl.SessionImpl.createQuery(SessionImpl.java:1650) [hibernate-core-3.3.1.GA.jar:3.3.1.GA]
    at com.smallworks.dao.impl.ContactDAOImpl.getContactList(ContactDAOImpl.java:92) [ContactDAOImpl.class:na]
    at com.smallworks.service.impl.ContactServiceImpl.getContactList(ContactServiceImpl.java:95) [ContactServiceImpl.class:na]
    at com.smallworks.controller.ProjectController.addContact(ProjectController.java:117) [ProjectController.class:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [na:1.6.0_33]
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) [na:1.6.0_33]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) [na:1.6.0_33]
    at java.lang.reflect.Method.invoke(Unknown Source) [na:1.6.0_33]
    at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176) [spring-web-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:426) [spring-webmvc-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:414) [spring-webmvc-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790) [spring-webmvc-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719) [spring-webmvc-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644) [spring-webmvc-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:560) [spring-webmvc-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:647) [servlet-api.jar:na]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:728) [servlet-api.jar:na]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305) [catalina.jar:7.0.33]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) [catalina.jar:7.0.33]
    at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:198) [spring-orm-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76) [spring-web-3.0.5.RELEASE.jar:3.0.5.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) [catalina.jar:7.0.33]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) [catalina.jar:7.0.33]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222) [catalina.jar:7.0.33]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123) [catalina.jar:7.0.33]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) [catalina.jar:7.0.33]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171) [catalina.jar:7.0.33]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99) [catalina.jar:7.0.33]
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:931) [catalina.jar:7.0.33]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) [catalina.jar:7.0.33]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407) [catalina.jar:7.0.33]
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004) [tomcat-coyote.jar:7.0.33]
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589) [tomcat-coyote.jar:7.0.33]
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312) [tomcat-coyote.jar:7.0.33]
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source) [na:1.6.0_33]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [na:1.6.0_33]
    at java.lang.Thread.run(Unknown Source) [na:1.6.0_33]
18:56:01.069 [http-bio-8080-exec-6] DEBUG o.s.o.h.s.OpenSessionInViewFilter - Closing single Hibernate Session in OpenSessionInViewFilter
18:56:01.069 [http-bio-8080-exec-6] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Closing Hibernate Session

回答1:

In the XML mapping Contact, the mapping of userSet is completely wrong:

<hibernate-mapping package="com.smallworks.model" schema="projectdb">
 <class name="Contact" table="CONTACT">
  <!-- ... --->
  <set inverse="true" lazy="false" name="userSet" sort="unsorted" table="USER_CONTACT">
    <key column="USER_ID"/>
    <many-to-many class="com.smallworks.model.Contact" column="CONTACT_ID" unique="false"/>
  </set>
 </class>
</hibernate-mapping>

It should be:

  <set inverse="true" lazy="false" name="userSet" sort="unsorted" table="USER_CONTACT">
    <key column="CONTACT_ID"/>
    <many-to-many class="com.smallworks.model.User" column="USER_ID" unique="false"/>
  </set>

It looks to me like you copy-and-pasted this from User and then didn't update it.

Why are you using XML rather than annotations? XML is much more error-prone, as you can see. In addition, a lot of these settings should be defaulted correctly by Hibernate. If you had just left out some of these attributes, it probably would have worked fine.



回答2:

Let's see if I understood right. You want to "get the Contacts associated with the User that is logged in." "I need to check on the Contact status...", correct?

If that is the case, try writing the query the other way around. So, you can start with the same query you have here . Let's suppose you want "All contacts with status 'ACTIVE' for the User that is logged in".

// First, retrieve the user you want.
User user = (User) session.get(User.class, user_id_you_want);
// Return only the conctats with status 'ACTIVE' 
List result = new ArrayList();
for(Contact c : contacts){
  if(c.getStatus().equals("ACTIVE")){
    result.add(c);
  }
}
return result;

I hope it helps...

===UPDATE1===

You are right, I thought a user would have a few contacts. How about if you try something like:

"FROM com.smallworks.model.User as u LEFT JOIN u.contacts as c WHERE u.userId=:userId AND c.status=:status"

Note that you may start your statement with "FROM" instead of "SELECT". See some good examples in this tutorial.

Another important reference: http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/queryhql.html

Additionally, note that in your case the class User owns the relationship, some statements need to take the ownership in consideration.