|
In our project Hibernate produces an invalid SQL statement under certain circumstances.
Let's assume the following classes/tables (very simplified, of course):
A --
OneToMany(eager) --> B ---OneToOne(eager)
--> C
A has a list of objects of type B, linked via a foreign key column in B. B is actually an abstract class having six subclasses. Here we use Single Table inheritance type, so all six subclasses are put into table B. Let's say the six classes are called B1...B6. B1 has an additional attribute of type 'date' while B2 has additionally a foreign key column pointing to table C. The other four subclasses B3...B6 should not be relevant. Now if we have an object A that has at least one object of type B1 (the one with the date value) in its 'B' list and we query this 'A' object, the error occurs. If we have a look into the SQL that is generated by Hibernate we see that the join from B to C is incorrect. Instead of joining from the foreign key column of B2 to the id column to C it joines from the Date column of B1 to the ID column of ID. This does of course not work because it cannot compare the 'Date' value with the ID column of C which is a 'BigInt'. The actual error message we get looks like this:
Cannot parse "TIMESTAMP" constant "10002303"; SQL statement:
select wizardinst0_.id as id1_106_0_, wizardinst0_.createdAt as createdA2_106_0_, wizardinst0_.CurrentWizardStepId as CurrentW7_106_0_, wizardinst0_.remarks as remarks3_106_0_, wizardinst0_.tenantId as tenantId4_106_0_, wizardinst0_.updatedAt as updatedA5_106_0_, wizardinst0_.userId as userId6_106_0_, wizardinst0_.WizardId as WizardId8_106_0_, wizardstep1_.id as id1_108_1_, wizardstep1_.name as name2_108_1_, wizardstep1_.position as position3_108_1_, wizardstep1_.WizardId as WizardId4_108_1_, wizard2_.id as id1_105_2_, wizard2_.description as descript2_105_2_, wizard2_.name as name3_105_2_, data3_.WizardInstanceId as WizardIn9_106_3_, data3_.id as id2_107_3_, data3_.id as id2_107_4_, data3_.name as name3_107_4_, data3_.WizardInstanceId as WizardIn9_107_4_, data3_.ValueDate as ValueDat4_107_4_, data3_.ValueBoolean as ValueBoo5_107_4_, data3_.MultiLingualStringId as MultiLi10_107_4_, data3_.ValueString as ValueStr6_107_4_, data3_.ValueDecimal as ValueDec7_107_4_, data3_.ValueInteger as ValueInt8_107_4_, data3_.discriminator as discrimi1_107_4_, multilingu4_.id as id1_96_5_, localizeds5_.MultiLingualStringId as MultiLin4_96_6_, localizeds5_.id as id1_97_6_, localizeds5_.language as formula1_6_, localizeds5_.id as id1_97_7_, localizeds5_.language as language2_97_7_, localizeds5_.MultiLingualStringId as MultiLin4_97_7_, localizeds5_.LocalizedText as Localize3_97_7_, wizard6_.id as id1_105_8_, wizard6_.description as descript2_105_8_, wizard6_.name as name3_105_8_ from STFSYS_WizardInstance wizardinst0_ inner join STFSYS_WizardStep wizardstep1_ on wizardinst0_.CurrentWizardStepId=wizardstep1_.id inner join STFSYS_Wizard wizard2_ on wizardstep1_.WizardId=wizard2_.id left outer join STFSYS_WizardInstanceData data3_ on wizardinst0_.id=data3_.WizardInstanceId left outer join STFSYS_MultiLingualString multilingu4_ on data3_.ValueDate=multilingu4_.id left outer join STFSYS_MultiLingualStringMap localizeds5_ on multilingu4_.id=localizeds5_.MultiLingualStringId inner join STFSYS_Wizard wizard6_ on wizardinst0_.WizardId=wizard6_.id where wizardinst0_.id=?
--> "10002303" is an ID in table C --> STFSYS_WizardInstance is 'A' --> STFSYS_WizardInstanceData is 'B' --> STFSYS_MultiLingualString is 'C' --> STFSYS_MultiLingualString.ValueDate is the 'Date' column of 'B1' --> STFSYS_MultiLingualString.MultiLingualStringId is the FK belonging to 'B2'
So instead of ... [...] left outer join STFSYS_MultiLingualString multilingu4_ on data3_.ValueDate=multilingu4_.id [...] ... it should be: [...] left outer join STFSYS_MultiLingualString multilingu4_ on data3_.MultiLingualStringId=multilingu4_.id [...]
This how the assocation between B2 and C is defined in the code:
@OneToOne(cascade = CascadeType.ALL, orphanRemoval=true, fetch = FetchType.EAGER) @JoinColumn(name="MultiLingualStringId") public MultiLingualString getValue() { return value; }
I have no clue why Hibernate uses 'ValueDate' as the join column, because in the code it is clearly defined as 'MultiLingualStringId'.
I hope all this information is enough to be able to reproduce the bug.
PS: My workmate told me for finding this bug we should be rewarded with a crate of beer. 
|