Hi Gordon,
If the @JoinColum refers the primary key column of SuperClass("ID" in this
case), it throws errors in current code.
First, There is an error in foreign key constraint generation.
[TopLink Warning]: 2006.11.17
07:07:26.663--ServerSession(10589182)--Thread(Thread[main,5,main])--Exception
[TOPLINK-4002] (Oracle TopLink Essentials - 9.1 (Build ${build_id})):
oracle.toplink.essentials.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: Constraint 'USERENTITYCHILD_ID'
is invalid: there is no unique or primary key constraint on table '
APP.CHILDCLASS' that matches the number and types of the columns in the
foreign key.Error Code: -1
Call:ALTER TABLE USERENTITY ADD CONSTRAINT USERENTITYCHILD_ID FOREIGN KEY
(CHILD_ID) REFERENCES CHILDCLASS (ID)
Query:DataModifyQuery()
Second, When inserting a row the following exception is thrown. This is
because OneToOneMapping has DatabaseField "CHILDCLASS.ID" as the target
field.
Exception [TOPLINK-45] (Oracle TopLink Essentials - 9.1 (Build
${build_id})): oracle.toplink.essentials.exceptions.DescriptorException
Exception Description: Missing mapping for field [CHILDCLASS.ID].
Descriptor: RelationalDescriptor(jpatests.model.inheritance.test.ChildClass-->
[DatabaseTable(SUPERCLASS), DatabaseTable(CHILDCLASS)])
at
oracle.toplink.essentials.exceptions.DescriptorException.missingMappingForField
(DescriptorException.java:886)
at
oracle.toplink.essentials.internal.descriptors.ObjectBuilder.extractValueFromObjectForField
(ObjectBuilder.java:1599)
at
oracle.toplink.essentials.mappings.OneToOneMapping.writeFromObjectIntoRow(
OneToOneMapping.java:1058)
at oracle.toplink.essentials.internal.descriptors.ObjectBuilder.buildRow
(ObjectBuilder.java:734)
at oracle.toplink.essentials.internal.descriptors.ObjectBuilder.buildRow
(ObjectBuilder.java:722)
at
oracle.toplink.essentials.internal.queryframework.DatabaseQueryMechanism.insertObjectForWrite
(DatabaseQueryMechanism.java:425)
at
oracle.toplink.essentials.queryframework.InsertObjectQuery.executeCommit(
InsertObjectQuery.java:74)
at
oracle.toplink.essentials.internal.queryframework.DatabaseQueryMechanism.performUserDefinedWrite
(DatabaseQueryMechanism.java:635)
at
oracle.toplink.essentials.internal.queryframework.DatabaseQueryMechanism.performUserDefinedInsert
(DatabaseQueryMechanism.java:599)
at
oracle.toplink.essentials.internal.queryframework.DatabaseQueryMechanism.insertObjectForWriteWithChangeSet
(DatabaseQueryMechanism.java:495)
at
oracle.toplink.essentials.queryframework.WriteObjectQuery.executeCommitWithChangeSet
(WriteObjectQuery.java:130)
at
oracle.toplink.essentials.internal.queryframework.DatabaseQueryMechanism.executeWriteWithChangeSet
(DatabaseQueryMechanism.java:283)
at
oracle.toplink.essentials.queryframework.WriteObjectQuery.executeDatabaseQuery
(WriteObjectQuery.java:67)
at oracle.toplink.essentials.queryframework.DatabaseQuery.execute(
DatabaseQuery.java:609)
at
oracle.toplink.essentials.queryframework.DatabaseQuery.executeInUnitOfWork(
DatabaseQuery.java:536)
at
oracle.toplink.essentials.queryframework.ObjectLevelModifyQuery.executeInUnitOfWorkObjectLevelModifyQuery
(ObjectLevelModifyQuery.java:123)
at
oracle.toplink.essentials.queryframework.ObjectLevelModifyQuery.executeInUnitOfWork
(ObjectLevelModifyQuery.java:95)
at
oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl.internalExecuteQuery
(UnitOfWorkImpl.java:2219)
at
oracle.toplink.essentials.internal.sessions.AbstractSession.executeQuery(
AbstractSession.java:937)
at
oracle.toplink.essentials.internal.sessions.AbstractSession.executeQuery(
AbstractSession.java:894)
at
oracle.toplink.essentials.internal.sessions.CommitManager.commitNewObjectsForClassWithChangeSet
(CommitManager.java:254)
at
oracle.toplink.essentials.internal.sessions.CommitManager.commitAllObjectsForClassWithChangeSet
(CommitManager.java:231)
at
oracle.toplink.essentials.internal.sessions.CommitManager.commitAllObjectsWithChangeSet
(CommitManager.java:187)
at
oracle.toplink.essentials.internal.sessions.AbstractSession.writeAllObjectsWithChangeSet
(AbstractSession.java:2638)
at
oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl.commitToDatabase(
UnitOfWorkImpl.java:1030)
at
oracle.toplink.essentials.internal.ejb.cmp3.base.RepeatableWriteUnitOfWork.commitToDatabase
(RepeatableWriteUnitOfWork.java:357)
at
oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet
(UnitOfWorkImpl.java:1112)
at
oracle.toplink.essentials.internal.ejb.cmp3.base.RepeatableWriteUnitOfWork.commitRootUnitOfWork
(RepeatableWriteUnitOfWork.java:82)
at
oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl.commitAndResume(
UnitOfWorkImpl.java:842)
at
oracle.toplink.essentials.internal.ejb.cmp3.transaction.base.EntityTransactionImpl.commit
(EntityTransactionImpl.java:90)
at
oracle.toplink.essentials.internal.ejb.cmp3.transaction.EntityTransactionImpl.commit
(EntityTransactionImpl.java:45)
at jpatests.tests.JpaTestBase.commitAndClose(JpaTestBase.java:92)
I think, metadata processing logic is probably assuming the target column
@JoinColumn is the column of the target table(CHILDCLASS) always.
Should either case work well? Or current way is right one?
Cheers,
-Wonseok
On 11/17/06, Gordon Yorke <gordon.yorke_at_oracle.com> wrote:
>
> Hello Wonseok,
> Either case should work in TopLink. I am not sure there is a
> "correct" way but I would expect customers to do either but most often
> reference the column of the subclass table. What is not working?
> --Gordon
>
> -----Original Message-----
> *From:* Wonseok Kim [mailto:guruwons_at_gmail.com]
> *Sent:* Thursday, November 16, 2006 7:24 AM
> *To:* persistence_at_glassfish.dev.java.net
> *Subject:* Re: JoinColumn of relationship with subclasses which has joined
> strategy?
>
> Comments inline...
>
> On 11/16/06, Wonseok Kim <guruwons_at_gmail.com> wrote:
> >
> > Hi all,
> > There is an interesting but not clear issue which Sahoo brought up.
> >
> > For example, there are entities which have Joined inheritance strategy.
> >
> > @Entity @Inheritance(strategy=JOINED)
> > public class SuperClass {
> > @Id @Column(name="ID") String id;
> > }
> >
> > @Entity @PrimaryKeyJoinColumn(name="PK", referencedColumnName="ID")
> > public class SubClass extends SuperClass {...}
> >
> > And if other entity references the Subclass like below,
> >
> > @Entity
> > public class User {
> > ...
> > @JoinColumn(name="USER_ID", referencedColumnName="???")
> > SubClass subClass;
> > }
> >
> > What should be the referencedColumnName value? Should it be the primary
> > column of SubClass table or SuperClass?
> > You can see below Sahoo's message.
> >
> > What do you think?
>
>
> My original understanding of the spec has been that referencedColumnName
> always refers to the column of the target entity's table.
> So "PK" (the primary key column of the SubClass) is, I think, right one.
>
> Spec: 9.1.6 JoinColumn Annotation says
> ...If the referencedColumnName element is missing, the foreign key is
> assumed to refer to the primary key of the referenced table.
>
> Table 8 in p.170 says
> referencedColumnName: (Optional) The name of the column referenced this
> foreign key column. When used with mappings, the column is in the table of
> the target entity.
>
> There is no mention about inheritance, but my interpretation is that the
> column of the target table should be used.
>
> Is there more clear idea?
>
> Thanks,
> -Wonseok
>
> On 16 Nov 2006 03:01:10 -0000, ss141213_at_dev.java.net <
> > ss141213_at_dev.java.net> wrote:
> > >
> > > https://glassfish.dev.java.net/issues/show_bug.cgi?id=1153
> > >
> > > ------- Additional comments from ss141213_at_dev.java.net Thu Nov 16
> > > 03:01:09 +0000 2006 -------
> > > Hi Wonseok,
> > >
> > > Although Table B has ID1 and ID2 as primary key columns and those two
> > > columns
> > > are also foreign keys to A.ID1 and A.ID2, but the IDs for the derived
> > > entity B
> > > should still be mapped to A.ID1 and A.ID2. That's my understanding. In
> > > the
> > > example below(thanks to Sherry Shen who brought this use case to my
> > > attention)
> > > where the columns in derived classes have been renamed to PK1 and PK2
> > > respectively, should the referencedColumnNames in @JoinTable be using
> > > PK1 and
> > > PK2 or ID1 and ID2? I think, they should be using ID1 and ID2 as shown
> > > below.
> > >
> > > @Embeddable class Person {
> > > String id1;
> > > String id2;
> > > }
> > >
> > > @Entity
> > > @Inheritance(strategy=JOINED)
> > > class Person {
> > > @EmbeddedId PersonPK personPK;
> > > ...
> > > }
> > >
> > > @Entity
> > > @PrimaryKeyJoinColumns({
> > > @PrimaryKeyJoinColumn(name="PK1", referencedColumnName="ID1"),
> > > @PrimaryKeyJoinColumn(name="PK2", referencedColumnName="ID2")
> > > })
> > > public class NaturalPerson {
> > > @ManyToMany(cascade=CascadeType.ALL)
> > > @JoinTable(name="PARENT_CHILDREN",
> > > joinColumns={
> > > @JoinColumn(name="P_ID1",
> > > referencedColumnName="ID1"),
> > > @JoinColumn(name="P_ID2",
> > > referencedColumnName="ID2")
> > > },
> > > inverseJoinColumns={
> > > @JoinColumn(name="C_ID1",
> > > referencedColumnName="ID1"),
> > > @JoinColumn(name="C_ID2",
> > > referencedColumnName="ID2")
> > > }
> > > )
> > > List<NaturalPerson> children;
> > > }
> > >
> > > With the current fix in place, this does not work. It works when we
> > > use PK1 and
> > > PK2 as the referenced column names in @JoinTable.
> > >
> > > Thanks,
> > > Sahoo
> > >
> >
> >
>