[hibernate-dev] On @OneToOne(optional=true) and @PrimaryKeyJoinColumn

Gail Badner gbadner at redhat.com
Wed Aug 24 22:10:57 EDT 2011


Responses inline...

----- Original Message -----
> From: "Emmanuel Bernard" <emmanuel at hibernate.org>
> To: "Gail Badner" <gbadner at redhat.com>
> Cc: hibernate-dev at lists.jboss.org
> Sent: Wednesday, August 24, 2011 4:21:39 PM
> Subject: Re: [hibernate-dev] On @OneToOne(optional=true) and @PrimaryKeyJoinColumn
> On 24 août 2011, at 23:17, Gail Badner wrote:
> 
> > @NotFound is Hibernate-specific, isn't it? Is there anything in the
> > JPA 2 spec that covers this functionality?
> 
> Nope, JPA 2 does not cover this case.
> 
> >
> > Since the default for @OneToOne is optional=true, it doesn't seem
> > right that it always be implicitly applied with
> > @PrimaryKeyJoinColumn, unless optional=false is explicitly
> > specified.
> >

Oops, I didn't mean: "unless option=false is explicitly specified" above. I meant: "unless @NotFound(IGNORE) is explicitly specified". 

> 
> Maybe you're right but I don't have the same rightness feeling.
> 
> Anyways, we can't rewrite history and we can differentiate not set
> from set to a value in Java's annotations. Besides, I suspect (has to
> be verified) that normal forms don't like null values even for foreign
> keys. This approach could be considered better though the proper
> approach would be to use a join table with unique constraints.

By "normal form" do you mean @OneToOne(optional=true) without a @PrimaryKeyJoinColumn or derived ID? If so, this case works fine; the foreign key column is nullable and the foreign key constraint is exported.

> 
> > Implicitly applying @NotFound(IGNORE) would break the default
> > mappings for unidirectional and bidirectional one-to-one
> > relationships documented in the spec.
> 
> Can you expand here. I don't follow you.
>

In 2.10.1 Bidirectional OneToOne Relationships:

The following mapping defaults apply:
Entity A is mapped to a table named A.
Entity B is mapped to a table named B.
Table A contains a foreign key to table B. The foreign key column name is formed as the con-
catenation of the following: the name of the relationship property or field of entity A; "_"; the
name of the primary key column in table B. The foreign key column has the same type as the
primary key of table B and there is a unique key constraint on it.

In 2.10.3.1 Unidirectional OneToOne Relationships:

The following mapping defaults apply:
Entity A is mapped to a table named A.
Entity B is mapped to a table named B.
Table A contains a foreign key to table B. The foreign key column name is formed as the con-
catenation of the following: the name of the relationship property or field of entity A; "_"; the
name of the primary key column in table B. The foreign key column has the same type as the
primary key of table B and there is a unique key constraint on it.

Implicitly applying @NotFound(IGNORE) would mean (I think) that we couldn't export the foreign key.

> >
> > It seems reasonable that the application would need to specify
> > @NotFound(IGNORE) to get this Hibernate-specific functionality.
> 
> There is a big difference. The many to one foreign key column pointing
> to a non existent entry is definitely bad form. I am not so sure about
> that in the PF/FK case (see above).
> 
> >
> > Here is my proposal:
> >
> > @OneToOne(optional=true) with @PrimaryKeyJoinColumn:
> >
> >   A) ID is generated (can only be foreign???)
> >      1) @OneToOne is NOT annotated with @NotFound(IGNORE)
> >         - ignore optional=true and log as INFO
> >         - export foreign key
> >         - load using an inner join
> 
> ok, log as WARN as the user should fix it.
> 
> >      2) @OneToOne is annotated with @NotFound(IGNORE)
> >         - throw an exception saying that @NotFound(IGNORE) is not
> >         allowed with generated IDs
> >
> 
> ok, log as WARN
> 
> >   B) ID is not generated
> >      1) @OneToOne is NOT annotated with @NotFound(IGNORE)
> >         - ignore optional=true and log as INFO
> >         - export foreign key
> >         - load using an inner join
> 
> That's where we disagree. I would honor optional=true in this case.
> That's not a case that we encounter that often
> 
> >      2) @OneToOne is annotated with @NotFound(IGNORE)
> >         - do not export foreign key
> >         - load using an outer join
> >
> 
> ok, log as WARN
> 
> > @OneToOne(optional=true) with derived identity
> >
> >   1) @OneToOne is NOT annotated with @NotFound(IGNORE)
> >      - ignore optional=true and log as INFO
> >      - export foreign key
> >      - load using an inner join
> >
> 
> ok, log as WARN
> 
> >   2) @OneToOne is annotated with @NotFound(IGNORE)
> >      - throw an exception saying that @NotFound(IGNORE) is not
> >      allowed with derived IDs
> >
> 
> ok, log as WARN
> 
> > What do you think?
> >
> > Gail
> > ----- Original Message -----
> > From: "Emmanuel Bernard" <emmanuel at hibernate.org>
> > To: hibernate-dev at lists.jboss.org
> > Sent: Wednesday, August 24, 2011 12:08:33 PM
> > Subject: [hibernate-dev] On @OneToOne(optional=true) and
> > @PrimaryKeyJoinColumn
> >
> > There is a distinction between optional=true and @NotFound
> >
> > I have had a few discussions with Gail on
> > https://hibernate.onjira.com/browse/HHH-4982 and
> > https://hibernate.onjira.com/browse/ANN-725
> > Don't spend too much time on these issue reports, they are very
> > confusing.
> >
> > The question boils down to whether or not @OneToOne(optional=true)
> > @PrimaryKeyJoinColumn is legal what the implication is on FK
> > constraint generation and inner vs outer join use to load the
> > object.
> >
> > Let's take the simple @ManyToOne example
> >
> >    @ManyToOne(optional=true) @JoinColumn(name="profile_fk")
> >    @NotFound(IGNORE)
> >    Profile getProfile() { ... };
> >
> > optional = true means that there may or may not be a Profile ie that
> > profile_fk is nullable
> > @NotFound(IGNORE) means that if profile_fk points to a profile that
> > is not present in the Profile table (say the fk = "emmanuel" and
> > there is no profile with "emmanuel" as a PK).
> >
> > @NotFound(IGNORE) is here to make Hibernate work on *broken*
> > databases where the DBA was smart enough to decide FK constraints
> > are useless.
> >
> > This one is easy.
> >
> > Now for true one to one these two concepts mix in
> >
> >    @Entity
> >    class User {
> >        @Id String username;
> >
> >        @OneToOne(optional=true) @PrimaryKeyJoinColumn
> >        Profile getProfile() { ... };
> >    }
> >
> > In this case, a User "emmanuel" has a profile whose primary key is
> > "emmanuel": the PK of User is also a foreign key pointing to
> > profile.
> >
> > Now it's perfectly reasonable to imagine that a User has no Profile
> > in which case, the User PK which is also the FK to profile would
> > point to a non existent entry in Profile. That would mean that we
> > cannot enforce the foreign key constraint.
> >
> > I think that for generated ids (via "foreign" or via derived
> > identity), we cannot have optional values. That would defeat the
> > purpose of the generator. In these case we should ignore
> > optional=true (and log a warning).
> >
> > For ids that are not generated, I'm torn. I see the use case above
> > as a decent use case for which we would not do to outer joins
> > instead of inner joins.
> > I think that the Hibernate engine reacts properly with the following
> > mapping
> >
> >    @Entity
> >    class User {
> >        @Id String username;
> >
> >        @OneToOne(optional=true) @PrimaryKeyJoinColumn
> >        @NotFound(IGNORE)
> >        Profile getProfile() { ... };
> >    }
> >
> > so we could make @NotFound(IGNORE) implicit when
> > @OneToOne(optional=true) @PrimaryKeyJoinColumn is found.
> >
> > Emmanuel
> > _______________________________________________
> > hibernate-dev mailing list
> > hibernate-dev at lists.jboss.org
> > https://lists.jboss.org/mailman/listinfo/hibernate-dev




More information about the hibernate-dev mailing list