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 <[email protected]> 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 <[email protected]> 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> > >
