Hi team,
I believe you had a good weekend.
I'm trying to fix the below issue 1153. The situation and cause of this
issue are explained in the below message, please see it.
To fix this, I added a map member to ObjectBuilder, which holds the
secondary key field(primary key field of the child table) and primary key
field(of the root table) mappings.
// Secondary key field to Primary key field map (joined inheritance or
secondary table)
protected Map primaryKeyFieldsBySecondaryField;
This map is used in ObjectBuilder.extractValueFromObjectForField() to get
the corresponding primary key field when the child entity's primary key
field was given.
/**
* Extract the value of the primary key attribute from the specified
object.
*/
public Object extractValueFromObjectForField(Object domainObject,
DatabaseField field, AbstractSession session) throws DescriptorException {
// Allow for inheritance, the concrete descriptor must always be
used.
ClassDescriptor descriptor = null;//this variable will be assigned
in the final
if (getDescriptor().hasInheritance() && (domainObject.getClass() !=
getDescriptor().getJavaClass()) && ((descriptor =
session.getDescriptor(domainObject)).getJavaClass()
!= getDescriptor().getJavaClass())) {
return
descriptor.getObjectBuilder().extractValueFromObjectForField(domainObject,
field, session);
} else {
DatabaseMapping mapping = getMappingForField(field);
if (mapping == null) {
throw DescriptorException.missingMappingForField(field,
getDescriptor());
}
// GF#1153
// If this entity is a child entity with JOINED inheritance
strategy and Embedded Id,
// getting value with the primary key field of child table won't
succeed
// for AggregateObjectMapping which only knows fields of root
entity's table.
// Therefore we use the primary key field of the root entity.
if(getDescriptor().isChildDescriptor() &&
mapping.isAggregateObjectMapping()){
DatabaseField primaryKeyField = (DatabaseField)
getPrimaryKeyFieldsBySecondaryField().get(field);
if(primaryKeyField != null) {
field = primaryKeyField;
}
}
return mapping.valueFromObject(domainObject, field, session);
}
}
I also added a new test for this - it required new models in 'inheritance'
package because there is no proper entity for this issue.
All entity-persistence tests including the new test passed with this fix.
There are diffs, all modified and new files in the attached file.
Please review!
Thanks
- Wonseok Kim
On 13 Oct 2006 11:54:28 -0000, guruwons_at_dev.java.net <guruwons_at_dev.java.net>
wrote:
>
> https://glassfish.dev.java.net/issues/show_bug.cgi?id=1153
>
> ------- Additional comments from guruwons_at_dev.java.net Fri Oct 13 11:54:28
> +0000 2006 -------
> This exception occurs for all types of relationships whose target is a
> child
> entity which has JOINED inheritance strategy and Embedded Id.
>
> Following are an exception example.
> ----------
> Caused by: Exception [TOPLINK-45] (Oracle TopLink Essentials - 9.1 (Build
> )):
> oracle.toplink.essentials.exceptions.DescriptorException
> Exception Description: Missing mapping for field [NATURALPERSON.ID].
> Descriptor: RelationalDescriptor(jpatests.model.Guid -->
> [DatabaseTable(PERSON)])
> at
>
> oracle.toplink.essentials.exceptions.DescriptorException.missingMappingForField
> (DescriptorException.java:885)
> at
>
> oracle.toplink.essentials.internal.descriptors.ObjectBuilder.extractValueFromObjectForField
> (ObjectBuilder.java:1584)
> at
> oracle.toplink.essentials.mappings.AggregateObjectMapping.valueFromObject(
> AggregateObjectMapping.java:912)
> at
>
> oracle.toplink.essentials.internal.descriptors.ObjectBuilder.extractValueFromObjectForField
> (ObjectBuilder.java:1587)
> at
> oracle.toplink.essentials.mappings.OneToOneMapping.writeFromObjectIntoRow(
> OneToOneMapping.java:1058)
> at
> oracle.toplink.essentials.internal.descriptors.ObjectBuilder.buildRow(
> ObjectBuilder.java:732)
> at
> oracle.toplink.essentials.internal.descriptors.ObjectBuilder.buildRow(
> ObjectBuilder.java:720)
> 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:2218)
> 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.commitAllObjectsWithChangeSet
> (CommitManager.java:175)
> 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)
> ... 26 more
> ----------
>
> CAUSE
>
> If entity B is a child entity of entity A which has composite primary key
> by
> @EmbeddedId, the internal class descriptor of B inherit mappings from the
> descriptor of A. Therefore B has same AggregateObjectMapping instance of
> entity
> A, and the AggregateObjectMapping instance has only fields of entity A.
> For
> example, if the primary key fields of A are A.ID1 and A.ID2 (table 'A'),
> and the
> primary key fields of B are B.ID1 and B.ID2, the AggregateObjectMapping
> has only
> A.ID1 and A.ID2.
>
> If ObjectBuilder.extractValueFromObjectForField() is called to get primary
> key
> value of child entity B with B.ID1, the AggregateObjectMapping doesn't
> find
> corresponding mapping with B.ID1 because it only knows A.ID1 and A.ID2. So
> an
> Exception like belwo is thrown.
>
> [TOPLINK-45] oracle.toplink.essentials.exceptions.DescriptorException
> Exception Description: Missing mapping for field [B.ID1].
>
> So we need to call ObjectBuilder.extractValueFromObjectForField() of
> AggregateObjectMapping with the field A.ID1 instead of given B.ID1.
>
> I'm working on the fix.
>
>