Bug 164 : wrong sql generated from criteria when entity with many-to-one assoc
Priority 
High
Reported Version 
 
Logged By 
imario
Status 
Fixed
Fixed Version 
2.2.0
Assigned To 
 
Product 
Ebean - core
Duplicate Of 
 
Created 
06/10/2009
Updated 
06/10/2009
Type 
Bug
 
Attachments 
No attachments

I have an entity with two ManyToOne proerties and try to make a query to this property using the criteria api.

This leads to a wrongly created sql as the join is added twice.

See the generated sql:
select t.ID c0, t.VERSION c1, t.SRCDATA c2, t.DSTDATA c3, t.EVENT_SOURCE_IDENTIFIER c4, ts.type c5, t.SRC c6, td.type c7, t.DST c8
from ops_topology t
left outer join ops_zones ts on ts.SID = t.SRC
left outer join ops_zones td on td.SID = t.DST
left outer join ops_zones td on td.SID = t.DST
left outer join ops_zones ts on ts.SID = t.SRC
where t.EVENT_SOURCE_IDENTIFIER = ? and ts.ZID = ? and td.ZID = ?


The reason is due to SqlTreeNodeBean where the join is added at line 428 and 432 where the appendFrom is called on the properties AND the children.

I am going to create a test case now.

 
imario 06 Oct 11:43
inheritance

Ok, the problem only shows up if the target property in the entity uses inheritance. In the above example the OPS_ZONES is twice in OPS_TOPOLOGY (namely SRC and DST) and OPS_ZONES itself has some subclasses.

In BeanPropertyAssocOne this forces the ebean to add the join, later then in SqlTreeNodeBean the join gets added again for each element in the "children" array.

imario 06 Oct 12:00
test committed

I've extended the TestInheritInsert by a testQuery() method.

This will show two bugs:

1) The VehicleDriver will not insert due to an NullPointerException regarding gettig the id.
2) If 1 is fixed, it will show the duplicate added join stuff due to the inheritance of "vehicle"


The NPE for 1:
java.lang.RuntimeException: get id on [com.avaje.tests.model.basic.Vehicle] type[com.avaje.tests.model.basic.Car] threw error.
at com.avaje.ebean.server.deploy.BeanProperty.getValue(BeanProperty.java:648)
at com.avaje.ebean.server.deploy.id.ImportedIdSimple.bind(ImportedIdSimple.java:103)
at com.avaje.ebean.server.persist.dmlbind.BindableAssocOne.dmlBind(BindableAssocOne.java:75)
at com.avaje.ebean.server.persist.dmlbind.BindableList.dmlBind(BindableList.java:62)
at com.avaje.ebean.server.persist.dml.InsertMeta.bind(InsertMeta.java:152)
at com.avaje.ebean.server.persist.dml.InsertHandler.bind(InsertHandler.java:124)
at com.avaje.ebean.server.persist.dml.DmlBeanPersister.execute(DmlBeanPersister.java:96)
at com.avaje.ebean.server.persist.dml.DmlBeanPersister.insert(DmlBeanPersister.java:74)
at com.avaje.ebean.server.persist.DefaultPersistExecute.executeInsertBean(DefaultPersistExecute.java:94)
at com.avaje.ebean.server.core.PersistRequestBean.executeNow(PersistRequestBean.java:341)
at com.avaje.ebean.server.core.PersistRequestBean.executeOrQueue(PersistRequestBean.java:371)
at com.avaje.ebean.server.persist.DefaultPersister.insert(DefaultPersister.java:256)
at com.avaje.ebean.server.persist.DefaultPersister.save(DefaultPersister.java:202)
at com.avaje.ebean.server.persist.DefaultPersister.saveRecurse(DefaultPersister.java:172)
at com.avaje.ebean.server.persist.DefaultPersister.save(DefaultPersister.java:161)
at com.avaje.ebean.server.core.DefaultServer.save(DefaultServer.java:1442)
at com.avaje.ebean.server.core.DefaultServer.save(DefaultServer.java:1432)
at com.avaje.ebean.Ebean.save(Ebean.java:522)
at com.avaje.tests.inheritance.TestInheritInsert.testQuery(TestInheritInsert.java:36)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:40)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:90)
Caused by: java.lang.NullPointerException
at com.avaje.ebean.server.deploy.BeanProperty.getValue(BeanProperty.java:640)
... 39 more

imario 06 Oct 12:02
the sql

As a workaround to get faster to 2 one can comment the line
driver.setVehicle(car)

Then the sql looks like this:

select v.id c0, v.name c1, v.cretime c2, v.updtime c3, vv.DTYPE c4, v.vehicle_id c5
from vehicle_driver v
left outer join vehicle vv on vv.id = v.vehicle_id
left outer join vehicle vv on vv.id = v.vehicle_id
where vv.license_number = ?

imario 06 Oct 12:17
forget NPE (1)

my project was not cleanly compiled. sorry.

imario 06 Oct 12:46
have a patch

by moving the addJoin from deploy.TableJoin into the DbSqlContext which than can keep track of which joins have been added I fixed it here.

I'll send the patch for review to Rob using email.

imario 06 Oct 12:47
NPE is back again

when using the maven build. Seems than subclassing is used instead of weaving and a bug is uncovered here? Building ebean using weaving with my IDE the NPE does not happen.

Rob 10 Oct 22:44
The NPE

Yes, the NPE is a bug. The ManyToOne is an inheritance hierarchy with the @Id property on an abstract class (the root of the inheritance tree is abstract). So this is the cause for the NPE - I'll log that as a separate bug.

Rob 10 Oct 23:10
Logged the NPE as Bug 166.

Rob 28 Oct 07:33
Fixed in HEAD

Fixed in HEAD.

woResponse

Upload a file