First time posting. Hope this is detailed enough.
I've been having issues with JPA Query parameter binding. In particular I find that my parameters are being scrambled.
In particular I am querying for Widget objects which stand in a ternary relation to Foo and Bar objects as a result of the Widget class having a Map typed properties field mapping Foo instances to Bar instances as follows:
Code:
public class Widget {
...
@id
int id;
String objectId
-- insert relevant annotations --
Map<Foo,Bar> properties;
...
}
Widgets, Foos, and Bars all have artificial keys and everything looks like I expect in the underlying rdbms (MySQL 5.1). I have four tables. One for each entity, and one for the table representing the Widget properties association.
My problem happens when I perform the following query:
Code:
select w
from widget w
where w.properties[ :foo0 ] = :bar0
and w.properties[ :foo1 ] = :bar1
Where the parameters are interpreted as follows:
foo0={foo instance with id = 8}
bar0={bar instance with id = 18}
foo1={foo instance with id = 4}
bar1={bar instance with id = 1038}
Note that foo0 != foo1, and bar0 != bar1.
When I try to run the above query (with the appropriate paramter settings), I discover that the EnitityManager/Session is scrambling the parameter binding. As seen here [more after log message]:
Code:
10:41:31,146 INFO Filter:405 - EJB-QL: select w from widget w where w.properties[ :foo0 ] = :bar0 and s.properties[ :foo1 ] = :bar1
10:41:31,146 INFO Filter:406 - params: {bar0={bar0 instance}, foo1= {foo0 instance}, bar1={bar1 instance}, foo0={foo0 instance}}
10:41:31,146 DEBUG SQL:401 -
select
series0_.id as id7_,
series0_.objectId as objectId7_
from
widget widget0_,
widget_foo_bar properties1_,
widget_foo_bar_associations properties2_
where
widget0_.id=properties1_.widget
and properties1_.foo = ?
and widget0_.id=properties2_.widget
and properties2_.foo = ?
and properties1_.bar=?
and properties2_.bar=?
10:41:31,146 DEBUG IntegerType:133 - binding '8' to parameter: 1
10:41:31,146 DEBUG IntegerType:133 - binding '8' to parameter: 1
10:41:31,146 DEBUG IntegerType:133 - binding '18' to parameter: 2
10:41:31,146 DEBUG IntegerType:133 - binding '18' to parameter: 2
10:41:31,161 DEBUG IntegerType:133 - binding '4' to parameter: 3
10:41:31,161 DEBUG IntegerType:133 - binding '4' to parameter: 3
10:41:31,161 DEBUG IntegerType:133 - binding '1038' to parameter: 4
10:41:31,161 DEBUG IntegerType:133 - binding '1038' to parameter: 4
10:41:31,161 INFO Filter:410 - query completed in 15 ms
The problem is that foo and bar id's aren't being bound to the correct widget_foo_bar_associations relation attributes.
The above binding would produce a query as follows:
Code:
select
series0_.id as id7_,
series0_.objectId as objectId7_
from
widget widget0_,
widget_foo_bar properties1_,
widget_foo_bar_associations properties2_
where
widget0_.id=properties1_.widget
and properties1_.foo = 8 -- foo0
and widget0_.id=properties2_.widget
and properties2_.foo = 18 -- bar0
and properties1_.bar=4 -- foo1
and properties2_.bar=1038 -- bar1
On the otherhand, what I'm expecting to see is the following:
Code:
select
series0_.id as id7_,
series0_.objectId as objectId7_
from
widget widget0_,
widget_foo_bar properties1_,
widget_foo_bar_associations properties2_
where
widget0_.id=properties1_.widget
and properties1_.foo = 8 -- foo0
and widget0_.id=properties2_.widget
and properties2_.foo = 4 -- foo1
and properties1_.bar= 18 -- bar0
and properties2_.bar=1038 -- bar1
So what is going on? I'm trying to be as thorough as possible. Is this a bug? Or am I missing something obvious?
Thanks for any help.
Carlos
p.s. My Query objects are constructed as follows (this might be relevant):
Code:
private Query buildQuery(final String jql,
final Map<String,Object> params,
final EntityManager em,
final boolean cache) {
Query q = em.createQuery(jql);
for (Map.Entry<String, Object> param : params.entrySet()) {
q.setParameter(param.getKey(), param.getValue());
}
if (cache) {
q.setHint("org.hibernate.cacheable", true);
}
return q;
}
private List getResults(final String jql,
final Map<String,Object> params,
final int offset,
final int limit,
final EntityManager em,
final boolean cache) {
Query q = this.buildQuery(jql, params, em, cache);
if (offset > 0 ) q.setFirstResult(offset);
if (limit < Integer.MAX_VALUE) q.setMaxResults(limit);
Logger logger = Logger.getLogger(this.getClass());
logger.info("querying for meta data...");
logger.info("EJB-QL: "+jql);
logger.info("params: "+params);
long start = new Date().getTime();
List lst = q.getResultList();
long end = new Date().getTime();
logger.info("query completed in "+(end-start)+" ms");
return lst;
}