Won't Fix
Details
Assignee
Koen AersKoen AersReporter
Joachim DurchholzJoachim DurchholzBug Testcase Reminder (view)
Bug reports should generally be accompanied by a test case!
Bug Testcase Reminder (edit)
Bug reports should generally be accompanied by a test case!
Participants
Joachim DurchholzJoachim DurchholzKoen AersComponents
Fix versions
Priority
Major
Details
Details
Assignee
Koen Aers
Koen AersReporter
Joachim Durchholz
Joachim DurchholzBug Testcase Reminder (view)
Bug reports should generally be accompanied by a test case!
Bug Testcase Reminder (edit)
Bug reports should generally be accompanied by a test case!
Participants
Joachim Durchholz
Joachim Durchholz
Koen Aers
Components
Fix versions
Priority
Created March 11, 2011 at 6:32 PM
Updated December 10, 2024 at 2:52 PM
Resolved December 10, 2024 at 2:52 PM
Hibernate tools does not always recognize one-to-one associations as such, even if specified as <one-to-one> in hibernate.reveng.xml.
1. It should generally not silently fall back to one-to-many or many-to-one if it determines that one-to-one is not possible; it should report an error instead. (This allows programmers to correct the database and/or the hibernate.reveng.xml: if it's really a one-to-many, they can move the association to the other table and make it many-to-one; if it should be one-to-one, they can add the missing constraints, giving Hibernate better information about the database schema actually in place.)
2. In the following test case, it does not recognize the relationship as one-to-one even though it is, erroneously generating a Set for the <inverse-one-to-one> direction instead of a backlink.
Workarounds:
A) Use <inverse-one-to-one exclude="true"/> to prevent Set creation. Works if you don't need the backlink.
B) Have a backlink field in the target table. Create two one-to-one associations, one for each direction, and use <inverse-one-to-one exclude="true"/>.
C) Do not reverse engineer the one-to-one association at all and use Criteria, HQL, or SQL to navigate the link.
D) Subclass DefaultReverseEngineeringStrategy and override isOneToOne() for that particular association.
Test case:
Table creation (Oracle 10g)
CREATE TABLE "HF_DI_BVKRIT" (
"BKID" NUMBER(27,0) NOT NULL ENABLE,
"VERSION" NUMBER(18,0) DEFAULT 0 NOT NULL ENABLE,
"BKNAME" VARCHAR2(40) NOT NULL ENABLE
) ;
ALTER TABLE "HF_DI_BVKRIT" ADD CONSTRAINT "HF_DI_BVKRIT_PK"
PRIMARY KEY ("BKID") ENABLE;
CREATE TABLE "HF_DI_BVKOPF" (
"BVID" NUMBER(10,0) NOT NULL ENABLE,
"VERSION" NUMBER(18,0) DEFAULT 0 NOT NULL ENABLE,
"BVBKID" NUMBER(27,0) NOT NULL ENABLE,
"BVGPRS" NUMBER(8,2)
) ;
ALTER TABLE "HF_DI_BVKOPF" ADD CONSTRAINT "HF_DI_BVKOPF_PK"
PRIMARY KEY ("BVID") ENABLE;
ALTER TABLE "HF_DI_BVKOPF" ADD CONSTRAINT "HF_DI_BVKOPF_UK"
UNIQUE ("BVBKID") ENABLE;
ALTER TABLE "HF_DI_BVKOPF" ADD CONSTRAINT "HF_DI_BVKOPF_FK_BVKRIT"
FOREIGN KEY ("BVBKID") REFERENCES "HF_DI_BVKRIT" ("BKID") ENABLE;
Relevant hibernate.reveng.xml section:
<table name="HF_DI_BVKOPF">
<column name="VERSION" type="long"></column>
<foreign-key constraint-name="HF_DI_BVKOPF_FK_BVKRIT">
<one-to-one />
<inverse-one-to-one />
</foreign-key>
</table>
Generated Java classes:
public class HfDiBvkrit implements java.io.Serializable {
private BigInteger bkid;
private long version;
private String bkname;
private Set <HfDiBvkopf> hfDiBvkopfs = new HashSet <HfDiBvkopf> (0);
// The above line should have been generated as:
// private HfDiBvkopf hfDiBvkopf;
...
}
public class HfDiBvkopf implements java.io.Serializable {
private BigInteger bvid;
private long version;
private HfDiBvkrit hfDiBvkrit;
private BigDecimal bvgprs;
...
}
Reasoning why this should be a one-to-one association (hopefully I didn't make too many errors reversing the roles of left and right table):
There is a unique key on BVKOPF.BVBKID.
I.e. a BVKRIT record can find at most one BVKOPF with a BVBKID that matches its BVKRIT.BKID.
The BVKOPF-BVKRIT association hence must be one-to-*. (1)
There is a foreign key from BVKOPF.BVBKID to BVKRIT.BKID.
BKID is a unique key in BVKRIT (it also happens to be the primary key, but that's irrelevant here).
I.e. a BVKOPF record can find at most one BVKRIT with a BKID that matches its BVKOPF.BVBKID.
The BVKOPF-BVKRIT association hence must be *-to-one. (2)
Combining (1) and (2) gives "must be one-to-one", q.e.d.
See also https://forum.hibernate.org/viewtopic.php?f=6&t=1009989&start=0