persistence@glassfish.java.net

Re: JPQL: fix query issue when navigating through two level of embeddeds

From: Michael Bouschen <Michael.Bouschen_at_Sun.COM>
Date: Fri, 02 Mar 2007 15:43:49 +0100

Hi Tom,

thanks for the details. I was not ware that there are different versions
of the descriptors for Embeddables. Does AggregateObjectMapping hold any
context information such that I can ask which version of the
AggregateObjectMapping I have. Otherwise it might become tricky since
the versions behave different.

I'm wondering what that means for the analysis of field access
expressions 'object.field' in the query compiler (and maybe other
components have a similar problem). Today the compiler gets the class
object representing the type of 'object'. It then resolves the mapping
of the field by retrieving the class descriptor for the class of
'object' and the calls getMappingForAttributeName passing the field
name. The mapping then allows to retrieve the type of the field.

I read your remark that just using the type of 'object' is not enough. I
need more context information, because I also also need the mapping of
'object' in order to get the correct version of the field mapping. Am I
right?

Regards Michael

> Hi Michael,
>
> I think I have discovered why you were seeing the issue with the
> reference descriptor of the contact field showing up as null.
>
> The issue occurs because of the fact that Aggregates (Embeddables)
> are handled in a special way in TopLink. Since Aggregates can be
> embedded in multiple different objects, their descriptors are stored
> in 2 ways.
>
> 1. The project contains a shell of the descriptor that holds all the
> information that is independant of where the Aggregate is Embedded.
> 2. The AggregateObjectMapping for each object that has the Aggregate
> embedded has a clone of the descriptor held in the project that has
> been updated with the information that is dependant of where the
> object is embedded.
>
> When you lookup Submission's descriptor you get a concrete descriptor
> for the Submission object. The Submission object has an
> AggregateObjectMapping for company. Since the Submission descriptor
> is a descriptor for an Entity, the AggregateObjectMapping holds the
> type of descriptor described in #2 above and as a result, has all the
> information.
>
> When you lookup Company's descriptor, you get an
> AggregateDescriptor. That descriptor contains an
> AggregateObjectMapping with a reference descriptor of type #1 above.
> That descriptor does not contain all the information.
>
> In order to get the correct information from the Company Descriptor,
> you have to get the descriptor through the Submission descriptor. You
> have to navigate through the Company mapping's descriptor and get the
> descriptor from the AggregateObjectMapping to Contact.
>
> -Tom
>
> Michael Bouschen wrote:
>
>> Hi Tom,
>>
>> I looked into issue 2463 "JPQL: cannot navigate through two level of
>> embeddeds": https://glassfish.dev.java.net/issues/show_bug.cgi?id=2462.
>>
>> The following query runs into an exception at runtime:
>> SELECT s.company.contact.firstName FROM Submission s
>> The select clause navigates two levels of embedded instances: contact
>> is embedded into company and company is embedded into submission. The
>> query compiler sets an outer join flag for this query and this
>> results in an exception that an outer join is invalid for a mapping
>> AggregateObjectMapping.
>>
>> The query compiler needs to set the outer join flag in case a
>> relationship field is selected in the SELECT clause. The current
>> implementation checks whether a selected field is *not* mapped as
>> DirectToFieldMapping. I changed this; now it checks whether it is a
>> relationship field mapping. You find the changes in the attached jar
>> fix2462.jar. Please have a look. I still need to add a test case to
>> entity-persistence-tests. This requires extending an existing entity
>> class, because today we do not have an entity with two level of
>> embeddeds.
>>
>> However, I was wondering why the old code (checking that the field is
>> not mapped as DirectToFieldMapping) did not work. I figured out that
>> both embedded fields Submission.company and Company.contact are
>> mapped as AggregateObjectMapping. But the reference descriptor of the
>> aggregate mapping for the contact field is null. So the code does not
>> get enough information to decide whether the firstName field in
>> Contact is a DirectToFieldMapping or not.
>>
>> Attached you find a test case running the above query for testing. I
>> also added a method printing the mapping of the two embedded fields
>> and its reference descriptors:
>> Submission.company
>> MAPPING
>> oracle.toplink.essentials.mappings.AggregateObjectMapping[company]
>> REFERENCE DESCRIPTOR RelationalDescriptor(test.pojo.Company -->
>> [DatabaseTable(SUBMISSION)])
>> Company.contact
>> MAPPING
>> oracle.toplink.essentials.mappings.AggregateObjectMapping[contact]
>> REFERENCE DESCRIPTOR null
>>
>> Regards Michael
>>
>>
>>
>>
>>
>