<one-to-one> should not generate Sets

Description

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

Environment

Hibernate Tools version as reported by Eclipse: 3.3.0.v20101016-0359-H111-Beta1 Feel free to identify the matching release numbers, I can't :-/

Activity

Show:

Koen AersDecember 10, 2024 at 2:52 PM

I am closing this issue as it did not have any relevant updates since 2011. Please feel free to reopen it if you think it is still relevant.

Joachim DurchholzMay 15, 2024 at 11:55 AM

Please remove *@durchholz.org from notifications.

I really don’t need one for this issue for every single frigging future update of Hibernate.

Joachim DurchholzFebruary 8, 2022 at 9:46 AM

Heh. Nice to see this is finally being addressed.

Joachim DurchholzMarch 14, 2011 at 4:04 PM

I just found out that the picture changes if the default setting of ON DELETE RESTRICT is changed to ON DELETE CASCADE: Reveng starts generating an additional association, a <many-to-one> with a <unique> tag, just as the hibernate book recommends.
However, the Pojo now contains two associations instead of one, which means Reveng is interpreting stuff in ways I don't understand, so it's not very useful to me. Worse, the new association again generates a Set on the other side of the association.
Unfortunately, I'm not sure whether I'm doing stuff wrong or hitting a Reveng bug, and since the reveng docs don't even mention the relevance of RESTRICT or CASCADE, I don't even know how it's supposed to work.

Won't Fix

Details

Assignee

Reporter

Bug 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