782 words

Object as parameter results in exception

#1
2011-04-27 12:15

Hi,

   I've got a simple JPA2 Criteria query which fails when doing an object equality. I verified this against EclipseLink and over there, it works. I'll Attach some code snippets to help figure it out:

 

@Entity()
public class Product{
   .
   .
   .
    @ManyToOne
    private Compamy owningCompany;
}
 
@Entity()
public class Company{
   .
   .
   .
    @Id
    private Long id; 
}

and the query:

 

 @Override
 public T fetch(Company company, Long primaryKey) {
  mLogger.info("Fetching type: {} with id {} with company: {}", new Object[]{managedClass, primaryKey, company});
  CriteriaBuilder qb = getEntityManager().getCriteriaBuilder();
  CriteriaQuery<T> c = qb.createQuery(managedClass);
  Root<T> p = c.from(managedClass);
  c.select(p);
  c.where(
    qb.equal(p.get("id"), primaryKey),
    qb.and(qb.equal(p.get("owningCompany"), company)));
  TypedQuery<T> q = getEntityManager().createQuery(c);
  List<T> resultList = q.getResultList();
  if(resultList.size() > 0){
   return resultList.get(0);
  }
  return null;
 }

The error I get is:

Caused by: com.objectdb.o.UserException: Unsupported query operator '@'
 at com.objectdb.o.MSG.d(MSG.java:61)
 at com.objectdb.o.TKR.t(TKR.java:383)
 at com.objectdb.o.TKR.r(TKR.java:149)
 at com.objectdb.o.TKI.<init>(TKI.java:53)
 at com.objectdb.o.QSP.<init>(QSP.java:77)
 at com.objectdb.o.QPR.H(QPR.java:979)
 at com.objectdb.o.QPR.<init>(QPR.java:102)
 at com.objectdb.o.QRC.<init>(QRC.java:116)
 at com.objectdb.o.QRM.UR(QRM.java:242)
 at com.objectdb.o.MST.UR(MST.java:878)
 at com.objectdb.o.WRA.UR(WRA.java:286)
 at com.objectdb.o.WSM.UR(WSM.java:113)
 at com.objectdb.o.STC.r(STC.java:418)
 at com.objectdb.o.SHN.ah(SHN.java:468)
 at com.objectdb.o.SHN.J(SHN.java:146)
 at com.objectdb.o.HND.run(HND.java:133)
 at java.lang.Thread.run(Thread.java:680)

Looking at the log:

[2011-04-28 04:18:07 #1900 query.manager]
<queryRequest query="SELECT $1 FROM Product $1 WHERE ($1.id=8) AND $1.owningCompany=com.x.y.z.Company@540ef9ef" args="null" transactionId="-1" />

So it seems, that it is doing a 'Company.toString()' on the instance instead of resolving the id? Have I misunderstood something again? Under eclipselink, this did work (going to PostgreSQL).

If I change my path expressions to point to basic java types (path expression pointing to id):

 

 @Override
 public T fetch(Company company, Long primaryKey) {
  mLogger.info("Fetching type: {} with id {} with company: {}", new Object[]{managedClass, primaryKey, company});
  CriteriaBuilder qb = getEntityManager().getCriteriaBuilder();
  CriteriaQuery<T> c = qb.createQuery(managedClass);
  Root<T> p = c.from(managedClass);
  c.select(p);
  c.where(
    qb.equal(p.get("id"), primaryKey),
    qb.and(qb.equal(p.get("owningCompany").get("id"), company.getId())));
  TypedQuery<T> q = getEntityManager().createQuery(c);
  List<T> resultList = q.getResultList();
  if(resultList.size() > 0){
   return resultList.get(0);
  }
  return null;
 }

 

I don't know if it's a bug, I just need help :)

 

Thanks

 

ObjectDB Version: 2.2.2_04

Willks
Willks's picture
Joined on 2011-04-04
User Post #7
#2
2011-04-27 13:04

This is an interesting question. It is unclear if your query is valid since objects such as a Company instance are expected to be passed to the query as parameters. Maybe EclipseLink defines an implicit parameter to resolve this query, and maybe this is what ObjectDB should do.

Using a parameter is also recommended for the primary key. In the current form the primary key is used as a literal, which means that the query has to be compiled every time and the query program cache cannot be used. Maybe ObjectDB should optimize such queries replacing literals with parameters automatically, whenever possible.

Currently, to solve the problem and improve efficiency please consider:

  • Building the query (the CriteriaQuery and the TypedQuery) once with two parameters.
  • Running the query by using the same prepared TypedQuery every time, setting two arguments.
ObjectDB Support
ObjectDB - Fast Object Database for Java (JPA/JDO)
support
support's picture
Joined on 2010-05-03
User Post #215
#3
2011-04-27 14:25

Yes that makes complete sense. Still migrating an application from JPA1 to JPA2 - and tat the same time making it run with ObjectDB.

So my solution now, is:

 

 @Override
 public T fetch(Company company, Long primaryKey) {
  mLogger.info("Fetching type: {} with id {} with company: {}", new Object[]{managedClass, primaryKey, company});
  CriteriaBuilder qb = getEntityManager().getCriteriaBuilder();
  CriteriaQuery<T> c = qb.createQuery(managedClass);
  Root<T> p = c.from(managedClass);
  c.select(p);
 
  ParameterExpression<Long> idParam = qb.parameter(Long.class);
  ParameterExpression<Company> companyParam = qb.parameter(Company.class);
 
  c.where(qb.equal(p.get("id"), idParam),
    qb.and(
      qb.equal(p.get("owningCompany"), companyParam)));
 
  TypedQuery<T> q = getEntityManager().createQuery(c);
  q.setParameter(idParam, primaryKey);
  q.setParameter(companyParam, company);
 
  List<T> resultList = q.getResultList();
  if(resultList.size() > 0){
   return resultList.get(0);
  }
  return null;
 }

 

So you recommend us to hold on to the TypedQuery? I see the value in not having to repeatedly execute the Criteria definitions. So ObjectDB would indeed cache this query the way it is?

Please ignore my original post - the literals are a pretty bad idea! Most of our queries will still be named queries, just our 'search' queries will be coded as Criteria queries.

Willks
Willks's picture
Joined on 2011-04-04
User Post #8
#4
2011-04-27 14:46

Your original post is of a great value since it highlights an important point and introduces the idea of replacing literals with parameters automatically - this is something that ObjectDB should do as optimization in next versions.

Your new implementation is good and since repeating invocations generate the same query - it will not be compiled by ObjectDB on every call and cache will be used.

Additional optimization can be achieved by:

  • Reusing a CriteriaQuery - creating it once per EntityManagerFactory.
  • Reusing a TypedQuery - creating it once per EntityManager (relevant when using long term EntityManager).

but the effect of this micro optimization is expected to be small, and irrelevant for criteria queries which are dynamic (i.e. the query structure changes between invocations).

ObjectDB Support
ObjectDB - Fast Object Database for Java (JPA/JDO)
support
support's picture
Joined on 2010-05-03
User Post #217
#5
2011-05-08 18:00

Are there any plans to implement the automatic replacement feature? I've run into the same issue but cannot rewrite the queries as they are created and handled by a third party library (I only pass the entity classes). My only option at the moment is to switch back to eclipselink/rdbms

 

 

ObjectDB version:  2.2.3_09

 

n0mad
n0mad's picture
Joined on 2011-05-08
User Post #1
#6
2011-05-09 00:48

This is now implemented in version 2.2.4. Please try it.

ObjectDB Support
ObjectDB - Fast Object Database for Java (JPA/JDO)
support
support's picture
Joined on 2010-05-03
User Post #258
#7
2011-05-10 06:49

I can now confirm that it works! Thank you very much for the prompt resolution.
 

n0mad
n0mad's picture
Joined on 2011-05-08
User Post #2

Post Reply

Please read carefully the posting instructions - before posting to the ObjectDB website.

  • You may have to disable pop up blocking in order to use the toolbar (e.g. in Chrome).
  • Use ctrl + right click to open the browser context menu in the editing area (e.g. for using a browser spell checker).
  • To insert formatted lines (e.g. Java code, stack trace) - select a style in the toolbar and then insert the text in the new created block.
  • Avoid overflow of published source code examples by breaking long lines.
  • You may mark in paragraph code words (e.g. class names) with the code style (can be applied by ctrl + D).
  • Long stack traces (> 50 lines) and complex source examples (> 100 lines) should be posted as attachments.
Attachments:
Maximum file size: 32 MB
Cancel