|
|
|
The problem here is very insidious, and multi-faceted. Consider an example:
{code:borderStyle=solid} @Entity public static class Company { @Id public Integer id; ... }
@Entity public static class Person { @Id public Integer id; @ManyToOne( cascade= CascadeType.ALL, optional = false ) @JoinColumn( name = "EMPLOYER_FK" ) public Company employer; ... } {code}
The first facet is the "nullability" of an attribute, here specifically an association. The first question is whether optional (i.e., {{OneToMany#optional}}) indicates the nullability of the underlying column. Today we treat it like it does. The JPA spec does not say either way. But (in our opinion) that makes the most sense.
When Hibernate needs to delete a related Person and Company, its preference is to: # UPDATE the PERSON table to set the EMPLOYER_FK column to null # perform the 2 deletions (the order is unimportant because of the UPDATE above).
However, given that interpretation of nullability of the {{PERSON.EMPLOYER_FK}} column as being {{NOT NULL}} as described above we "know" that we cannot do the UPDATE listed first. Really the 2 deletes would need to be ordered properly for them to succeed. Now, if we allow the cascade to occur and simply delete Person that actually happens, Hibernate properly orders the deletions for us. However lets say the application does this:
{code:borderStyle=solid} Person p = ...; em.remove( p.company ); em.remove( p ); {code}
Here the ordering has been set (incorrectly) by the app. And given the {{optional=false}} case being described, this will result in an error.
The current error the app would see is an exception like: {noformat} org.hibernate.PropertyValueException: not-null property references a null or transient value ... {noformat}
That comes about because of some explicit nullability checking in {{org.hibernate.event.internal.DefaultDeleteEventListener#deleteEntity}}. But even if we remove that explicit checking, the above would fail because of the bad ordering of the SQL DELETE statements.
Ideally we would have 2 paths here. The first path would do that UPDATE+DELETE scenario when the attribute is defined as optional. The second path would sort the DELETIONS into a proper order.
|
|
|
|