-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 1 post ] 
Author Message
 Post subject: JPA2 Criteria API, using Entity as query parameter.
PostPosted: Mon Nov 15, 2010 12:40 pm 
Newbie

Joined: Mon Nov 15, 2010 9:54 am
Posts: 1
I've been trying to implement QBE (Query by Example) functionality using plain JPA2 spec, while using Hibernate 3.5.5 as JPA2 implementaion. The problem i am stumbled upon is the following:
I have implemented GenericDao<T> with the following methods:

Code:
   
   public List<T> findByExample(T exampleInstance) {

      TypedQuery<T> query = getQueryByExample(exampleInstance);
      if (query == null)
         return null;
      else
         return query.getResultList();
   }


private TypedQuery<T> getQueryByExample(T exampleInstance) {
      try {
         CriteriaBuilder cb = entityManager.getCriteriaBuilder();
         CriteriaQuery<T> c = cb.createQuery(persistentClass);
         Root<T> r = c.from(persistentClass);

         Predicate p = cb.conjunction();
         if (exampleInstance != null) {
            Metamodel mm = entityManager.getMetamodel();
            EntityType<T> et = mm.entity(persistentClass);
            Set<Attribute<? super T, ?>> attrs = et.getAttributes();

            for (Attribute<? super T, ?> a : attrs) {
               String name = a.getName();
               String javaName = a.getJavaMember().getName();
               String getter = "get"
                     + javaName.substring(0, 1).toUpperCase()
                     + javaName.substring(1);
               Method m;

               m = persistentClass.getMethod(getter, (Class<?>[]) null);

               if (m.invoke(exampleInstance, (Object[]) null) != null)
                  p = cb.and(p, cb.equal(r.get(name), m.invoke(
                        exampleInstance, (Object[]) null)));
            }
         }
         c.select(r).where(p);
         TypedQuery<T> query = entityManager.createQuery(c);
         return query;

      } catch (SecurityException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      } catch (NoSuchMethodException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      } catch (IllegalArgumentException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      } catch (IllegalAccessException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      } catch (InvocationTargetException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }
      return null;

   }


It works fine for Entities with simple properties, when examples of such entities are passed to this method, but if say, we have Entity1 which has field of type Entity2:

@OneToOne
@JoinColumn(name = "entity2_id", nullable = false)
private Entity2 entity2;

If we do the following :

Code:
Entity1 example=new Entity1();
Enitity2 example2= new Entity2();
example.setEntity2(example2);
new GenericDao<Entity1>.findByExample(example);




It fails with the following exception:


javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not execute query
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1179)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1112)
at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:245)
at org.hibernate.ejb.criteria.CriteriaQueryCompiler$3.getResultList(CriteriaQueryCompiler.java:187)
.......................
at ................................
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at junit.framework.TestCase.runTest(TestCase.java:168)
at org.jmock.core.VerifyingTestCase.runBare(Unknown Source)
at junit.framework.TestResult$1.protect(TestResult.java:110)
at junit.framework.TestResult.runProtected(TestResult.java:128)
at junit.framework.TestResult.run(TestResult.java:113)
at junit.framework.TestCase.run(TestCase.java:124)
at junit.framework.TestSuite.runTest(TestSuite.java:232)
at junit.framework.TestSuite.run(TestSuite.java:227)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:79)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.hibernate.exception.SQLGrammarException: could not execute query
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:92)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.loader.Loader.doList(Loader.java:2297)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2172)
at org.hibernate.loader.Loader.list(Loader.java:2167)
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:448)
at org.hibernate.hql.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:363)
at org.hibernate.engine.query.HQLQueryPlan.performList(HQLQueryPlan.java:196)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1258)
at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102)
at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:236)
... 26 more
Caused by: java.sql.SQLException: Wrong data type: java.lang.NumberFormatException: For input string: "[B@12cd8d4"
at org.hsqldb.jdbc.Util.throwError(Unknown Source)
at org.hsqldb.jdbc.jdbcPreparedStatement.setParameter(Unknown Source)
at org.hsqldb.jdbc.jdbcPreparedStatement.setBytes(Unknown Source)
at org.hibernate.type.AbstractBynaryType.set(AbstractBynaryType.java:66)
at org.hibernate.type.SerializableType.set(SerializableType.java:52)
at org.hibernate.type.NullableType.nullSafeSet(NullableType.java:154)
at org.hibernate.type.NullableType.nullSafeSet(NullableType.java:136)
at org.hibernate.param.NamedParameterSpecification.bind(NamedParameterSpecification.java:67)
at org.hibernate.loader.hql.QueryLoader.bindParameterValues(QueryLoader.java:567)
at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1612)
at org.hibernate.loader.Loader.doQuery(Loader.java:717)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:270)
at org.hibernate.loader.Loader.doList(Loader.java:2294)
... 34 more

The reason for this is that it takes the query constructed with CriteriaBuilder, and which looks something like:

select generatedAlias0 from ENTITY1 as generatedAlias0 where ( 1=1 ) and ( generatedAlias0.Entity2=:param0 )

Transforms it to SQL:

select Entity1.field1, Entity1.field2, .... from Entity1_Table Entity1 where 1=1 and Entity1 .entity2_id=?

Which itself is incorrect, since it does not try to parametrize all the fields of Entity2 but ID only, afterwards

it tries to replace parameter with example2.toString() obviously failing hard.


Any ideas?


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 1 post ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.