cayenne-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Andrus Adamchik <and...@objectstyle.org>
Subject Re: Problem with joint prefetch and flattened attributes
Date Wed, 06 Aug 2014 06:40:14 GMT
Actually, checking the release notes [1], we have a bunch of prefetch-related fixes in (yet
unreleased) 3.2M2 - CAY-1928, CAY-1695, CAY-1905. 1905 and 1928 are also fixed on 3.1 branch

Could you maybe try your case with a source code build of Cayenne (either 3.1 or master) ?

Thanks,
Andrus

[1] https://github.com/apache/cayenne/blob/master/docs/doc/src/main/resources/RELEASE-NOTES.txt
[2] https://github.com/apache/cayenne/blob/STABLE-3.1/docs/doc/src/main/resources/RELEASE-NOTES.txt

On Aug 6, 2014, at 9:34 AM, Andrus Adamchik <andrus@objectstyle.org> wrote:

>> This is clearly a bug. Should I create a JIRA issue?
> 
> Hi Erlend,
> 
> Yes, please Jira it. Sounds like a bug.
> 
> Thanks,
> Andrus
> 
> 
> On Aug 5, 2014, at 2:07 PM, Erlend Birkenes <eb@dataloy.com> wrote:
> 
>> Hi
>> 
>> I discovered a problem with joint prefetch and flattened attributes. This
>> is in 3.1B2 which is the version we use at the moment. Not sure if this is
>> the lates or not..
>> 
>> If I have a entity A with a normal relationship to an entity B, and B has
>> flattened attributes from C via toCdbrel.SOME_PROPERTY.
>> This works fine normally. But when using joint prefetch the table aliases
>> in the query will be wrong. (Querying A and prefetching B).
>> If there are multiple flattened attributes, C will also be joined in
>> multiple times.
>> 
>> The problem is in SelectTranslator#appendQueryColumns.
>> This section adds columns from the target entity of a joint prefetch,
>> including relationships for flattened attributes:
>> 
>> while (targetObjAttrs.hasNext()) {
>>       ObjAttribute oa = targetObjAttrs.next();
>>       Iterator<CayenneMapEntry> dbPathIterator = oa.getDbPathIterator();
>>       while (dbPathIterator.hasNext()) {
>>               Object pathPart = dbPathIterator.next();
>> 
>>               if (pathPart == null) {
>>                       throw new CayenneRuntimeException(
>>                                       "ObjAttribute has no component: " +
>> oa.getName());
>>               }
>>               else if (pathPart instanceof DbRelationship) {
>>                       DbRelationship rel = (DbRelationship) pathPart;
>>                       dbRelationshipAdded(rel, JoinType.INNER, null);
>> //PROBLEM
>>               }
>>               else if (pathPart instanceof DbAttribute) {
>>                       DbAttribute attribute = (DbAttribute) pathPart;
>> 
>>                       appendColumn(columns, oa, attribute, attributes,
>> labelPrefix
>>                                       + '.'
>>                                       + attribute.getName());
>>               }
>>       }
>> }
>> 
>> The problem is that dbRelationshipAdded sets the topNode of the JoinStack
>> to the new node when a relationship is added and this is never reset in
>> this case. So every time a relationship is added in this loop it will add a
>> node to the previously added node. This will increase the tableAlias by 1
>> for every relationship, and also cause any attributes directly on B to
>> belong to the wrong node and therefore get the wrong tableAlias. It will
>> also cause an additional join, but joined to the wrong table.
>> 
>> The topNode of the JoinStack needs to be reset to the correct value after
>> handing each attribute, or more presisely: after the "while
>> (dbPathIterator.hasNext())" loop the topNode needs to be the same as it was
>> before the loop, because we are still processing attributes on the same
>> entity (B in this case).
>> 
>> Storing the current topNode, and resetting it after processing each
>> attribute fixed the problem for me. Like this:
>> 
>> while (targetObjAttrs.hasNext()) {
>>                   JoinTreeNode topNode = getJoinStack().topNode;  // FIX
>>                   ObjAttribute oa = targetObjAttrs.next();
>>                   Iterator<CayenneMapEntry> dbPathIterator =
>> oa.getDbPathIterator();
>>                   while (dbPathIterator.hasNext()) {
>>                       Object pathPart = dbPathIterator.next();
>> 
>>                       if (pathPart == null) {
>>                           throw new CayenneRuntimeException(
>>                                   "ObjAttribute has no component: " +
>> oa.getName());
>>                       }
>>                       else if (pathPart instanceof DbRelationship) {
>>                           DbRelationship rel = (DbRelationship) pathPart;
>>                           dbRelationshipAdded(rel, JoinType.INNER, null);
>>                       }
>>                       else if (pathPart instanceof DbAttribute) {
>>                           DbAttribute attribute = (DbAttribute) pathPart;
>> 
>>                           appendColumn(columns, oa, attribute,
>> attributes, labelPrefix
>>                                   + '.'
>>                                   + attribute.getName());
>>                       }
>>                   }
>>                   getJoinStack().topNode = topNode; // FIX
>>               }
>> 
>> resetJoinStack() can't be used in this case, since we don't want the
>> rootNode.
>> 
>> I've run the Cayenne tests after this change with no errors, but I've only
>> done limited testing in our own app so far.
>> 
>> This is clearly a bug. Should I create a JIRA issue?
>> 
>> 
>> –
>> Erlend <http://www.dataloy-systems.com>
> 
> 


Mime
View raw message