Comments below... On Sun, Sep 2, 2018 at 11:17 PM, Vlad Mihalcea <mihalcea.v...@gmail.com> wrote:
> Here are my comments: > > 1. I think the @MapsId behavior is the right one even if we don't enable > cascading on the child-side. > Although theoretically, we should not do that, in reality, if we disable > this behavior, some apps will break. > I don't know the history of why cascade-persist is forced. I see 2 jiras related to this (HHH-4858, HHH-4887). Emmanuel, can you provide some information about why this was added for @MapsId, but not @PrimaryKeyJoinColumn? I don't see anything in the spec about this. Am I missing something? I agree that removing cascade-persist from @MapsId now would cause applications to break. If this is Hibernate-specific behavior then shouldn't this functionality be enabled/disabled via a property ( e.g., hibernate.jpa.compliance.cascade_persist_id_associations) and JpaCompliance? The default would be "enabled". > > We could document the behavior so that, when used @MapdId or PKJC, > Hibernate is allowed to cascade the parent if it's transient. > > Do we really want to add this functionality with @PKJC at this point, since @MapsId is preferred, and cascade=CascadeType.PERSIST can easily be added to @OneToOne. > 2. According to the JPA spec, the @OneToOne optional attribute is defined > like this: > > (Optional) Whether the association is optional. >> If set to false then a non-null relationship must >> always exist. > > > I don't think that `optional` should be related to the FK generation. For > me, `optional` is more like adding NOT NULL to the FK column. > I think in this particular case, it is important. With the following mapping: @Entity public class ChildPKJC { @Id private Long id; @OneToOne // note that cascade-persist is not enabled @PrimaryKeyJoinColumn private Parent parent; } If ChildPKJC#parent is null, that means that ChildPKJC#id has a non-null value that does not correspond to a Parent ID. If this happens and there is a foreign key constraint, a constraint violation would occur. It seems to me that the spec supports this use case with @PKJC, and annotating with @NotFound(IGNORE) should not be necessary. Emmanuel, do you agree? Should using @MapsId instead of @PKJC work the same way? > 3. This reminds me of this Jira issue: > > https://hibernate.atlassian.net/browse/HHH-12770 > > I guess it makes sense to have what you proposed: > > Is this expected? If so, then ChildMapsId#parent cannot be optional by >> default (without @NotFound(IGNORE). > > > As for these questions: > > 1) the application must initialize ChildPKJC#id before persisting the >> entity [1]; otherwise, the following exception is thrown: >> javax.persistence.PersistenceException: >> org.hibernate.id.IdentifierGenerationException: ids for this class must >> be >> manually assigned before calling save(): > > > This is a consequence of the current behavior. I've added this phrase to > explain what happens. > If we change the behavior, we should update the doc too. > > Related to: > > [2] Section 2.4.1 Primary Keys Corresponding to Derived Identities of the >> spec has this footnote: >> [12] If the application does not set the primary key attribute >> corresponding to the relationship, the value of that attribute may not be >> available until after the entity has been flushed to the database. > > > They say "may not", meaning that setting the ID prior to flushing is not > going to break the spec. > For @MapsId, the spec seems to say that, if the application doesn't assign the ID attributes corresponding to a relationship, the persistence provider will assign ID attributes during flush (at the latest). I find the documentation on this topic to be confusing, so maybe I'm missing something. I don't see anything in the spec that this same behavior is expected for @PKJC. Emmanuel, please confirm. > > For sequence identifiers, we always get the ID generated prior to the > flush anyway. > > And for: > > [3] Section 11.1.44 PrimaryKeyJoinColumn Annotation has a footnote: >> [121]It is not expected that a database foreign key be defined for the >> OneToOne mapping, as the OneToOne relationship may be defined as >> “optional=true”. > > > I don't think that makes any sense at all. The real one-to-one database > table relationship is supposed to use a FK. > Now, without MapsId or PKJC, we actually have a "one-to-many" table > relationship with a UNIQUE constraint. > Even so, the FK is always mandatory. I have no idea why the JPA spec says > that. > Please see what I wrote above about this. Thanks, Gail > > Vlad > > > On Sat, Sep 1, 2018 at 10:33 AM, Gail Badner <gbad...@redhat.com> wrote: > >> FWIW, I've already spent a lot of time looking into the possible bugs I've >> described. I have a good idea about how to fix each one, so there's no >> need >> to research these. At this point, I'm just trying to get confirmation of >> whether they really are bugs. >> >> On Sat, Sep 1, 2018 at 12:21 AM, Gail Badner <gbad...@redhat.com> wrote: >> >> > FYI, I am taking PTO Tuesday, 9/4. I hope to be able to move forward on >> > this when I return on 9/5. >> > >> > I see some differences. Some may be expected, but I think there are some >> > bugs. >> > >> > For example, suppose we have the following entities: >> > >> > @Entity >> > public class Parent { >> > @Id >> > private Long id; >> > } >> > >> > @Entity >> > public class ChildPKJC { >> > @Id >> > private Long id; >> > >> > @OneToOne // note that cascade-persist is not enabled >> > @PrimaryKeyJoinColumn >> > private Parent parent; >> > } >> > >> > public class ChildMapsId { >> > @Id >> > private Long id; >> > >> > @OneToOne // note that cascade-persist is not enabled >> > @MapsId >> > private Parent parent; >> > } >> > >> > ------------------------------------------------------------ >> > ------------------------------------------------------------ >> > ------------------- >> > >> > When persisting ChildPKJC: >> > >> > 1) the application must initialize ChildPKJC#id before persisting the >> > entity [1]; otherwise, the following exception is thrown: >> > javax.persistence.PersistenceException: org.hibernate.id.IdentifierGen >> erationException: >> > ids for this class must be manually assigned before calling save(): >> > >> > 2) if ChildPKJC#parent is new with an assigned ID, and ChildPKJC#id is >> > assigned parent's ID, the ChildPKJC Entity is persisted with the >> parent's >> > ID, but parent is not persisted. >> > >> > When persisting ChildMapsId: >> > >> > 1) Hibernate automatically initializes ChildMapsId#id to parent.id [2] >> > >> > 2) if ChildMapsId#parent is new, parent is automatically >> > cascade-persisted (even though CascadeStyle.PERSIST is not mapped), then >> > the ChildMapsId entity is persisted. >> > >> > Are these expected difference? (My guess is yes) >> > >> > ------------------------------------------------------------ >> > ------------------------------------------------------------ >> > ------------------- >> > >> > Foreign key generation: >> > >> > If ChildPKJC#parent is optional there is no foreign key generated from >> ChildPKJC >> > referencing Parent. [3] If ChildPKJC#parent is not optional, a foreign >> > key is generated >> > >> > For ChildMapsId, a foreign key is generated from ChildPKJC referencing >> > Parent, even if ChildMapsId#parent is optional. >> > >> > Is this a bug? My guess is that it is. >> > >> > Adding the following mapping to ChildMapsId#parent works to disable >> > foreign key generation: >> > @JoinColumn(foreignKey = @ForeignKey(value = >> ConstraintMode.NO_CONSTRAINT)) >> > >> > (can be used as a workaround) >> > >> > ------------------------------------------------------------ >> > ------------------------------------------------------------ >> > ------------------- >> > >> > Loading an existing ChildPKJC/ChildMapsId with an optional Parent >> > association by ID, when there is no Parent entity with the same ID >> (IIUC, >> > this is the only way that ChildPKJC#parent or ChildMapsId#parent can be >> > optional [3]): >> > >> > For ChildPKJC, the loaded ChildPKJC entity will have a null parent. >> There >> > is no need to add @NotFound(IGNORE) to ChildPKJC#parent. >> > >> > If ChildPKJC#parent is optional, it is always eagerly loaded. >> > >> > This makes sense, since we cannot create a proxy if there is the >> > possibility of a null Parent entity. >> > >> > For ChildMapsId, the loaded value will be null because >> ObjectNotFoundException >> > will be thrown when Hibernate tries to load the Parent entity. >> > Adding @NotFound(IGNORE) to ChildMapsId#parent will result in >> ChildMapsId >> > entity being loaded with a null parent association. >> > >> > Is this expected? If so, then ChildMapsId#parent cannot be optional by >> > default (without @NotFound(IGNORE). >> > >> > I think it would make more sense if the ChildMapsId entity is loaded >> with >> > a null parent association, consistent with what happens for ChildPKJC. >> If >> > we go that route, then ChildMapsId#parent will always have to be loaded >> > eagerly. >> > >> > ------------------------------------------------------------ >> > ------------------------------------------------------------ >> > ------------------- >> > >> > Please let me know your thoughts on this. >> > >> > [1] this requirement is documented in Example 178. Derived identifier >> > @PrimaryKeyJoinColumn with a note that says: "Unlike @MapsId, the >> > application developer is responsible for ensuring that the identifier >> and >> > the many-to-one (or one-to-one) association are in sync as you can see >> in >> > the PersonDetails#setPerson method." >> > >> > [2] Section 2.4.1 Primary Keys Corresponding to Derived Identities of >> the >> > spec has this footnote: >> > [12] If the application does not set the primary key attribute >> > corresponding to the relationship, the value of that attribute may not >> be >> > available until after the entity has been flushed to the database. >> > >> > [3] Section 11.1.44 PrimaryKeyJoinColumn Annotation has a footnote: >> > [121]It is not expected that a database foreign key be defined for the >> > OneToOne mapping, as the OneToOne relationship may be defined as >> > “optional=true”. >> > >> > >> > On Fri, Aug 31, 2018 at 1:29 PM, Gail Badner <gbad...@redhat.com> >> wrote: >> > >> >> The fix for HHH-12436 involves correcting the foreign key direction for >> >> "real" one-to-one associations. I've been looking into the >> ramifications of >> >> this change because I'm concerned that applications can rely on the old >> >> (incorrect) foreign key direction. >> >> >> >> In the process I've found that Hibernate treats: >> >> >> >> @OneToOne >> >> @PrimaryKeyJoinColumn >> >> private Employee employee; >> >> >> >> differently from: >> >> >> >> @OneToOne >> >> @MapsId >> >> private Employee employee; >> >> >> >> I believe they should be treated consistently. You can see my reasoning >> >> below. [1] >> >> >> >> Before going into details about how they are treated differently, I'd >> >> like to get confirmation, in case I am missing some subtlety. >> >> >> >> Could someone please confirm this? >> >> >> >> Regards, >> >> Gail >> >> >> >> ------------------------------------------------------------ >> >> --------------------------------- >> >> [1] >> >> >> >> In 2.4.1.3 Examples of Derived Identities, Example 4(b) uses MapsId >> >> without the value element as follows: >> >> >> >> @MapsId >> >> @JoinColumn(name="FK") >> >> @OneToOne Person patient; >> >> >> >> This example has the following footnote: >> >> "[15] Note that the use of PrimaryKeyJoinColumn instead of MapsId would >> >> result in the same mapping in this example. Use of MapsId >> >> is preferred for the mapping of derived identities." >> >> >> >> The description has a footnote that says that using >> PrimaryKeyJoinColumn >> >> instead of MapsId would result in the same mapping. >> >> >> >> In 11.1.45 PrimaryKeyJoinColumns Annotation, Example 2 uses >> >> @PrimaryKeyJoinColumns as follows: >> >> >> >> @OneToOne >> >> @PrimaryKeyJoinColumns({ >> >> @PrimaryKeyJoinColumn(name="ID", >> >> referencedColumnName="EMP_ID"), >> >> @PrimaryKeyJoinColumn(name="NAME", >> >> referencedColumnName="EMP_NAME")}) >> >> EmployeeInfo info; >> >> >> >> This example has the following footnote: >> >> "[123]Note that the derived identity mechanisms decribed in section >> >> 2.4.1.1 is now preferred to the use of PrimaryKeyJoinColumn for >> >> this case." >> >> >> >> >> _______________________________________________ >> hibernate-dev mailing list >> hibernate-dev@lists.jboss.org >> https://lists.jboss.org/mailman/listinfo/hibernate-dev >> > > _______________________________________________ hibernate-dev mailing list hibernate-dev@lists.jboss.org https://lists.jboss.org/mailman/listinfo/hibernate-dev