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

Emmanuel Bernard emmanuel at hibernate.org
Wed Aug 24 19:21:39 EDT 2011


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.  
> 

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.

> 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.

> 
> 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