You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cayenne.apache.org by Erlend Birkenes <eb...@dataloy.com> on 2014/08/05 13:07:49 UTC

Problem with joint prefetch and flattened attributes

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>

Re: Problem with joint prefetch and flattened attributes

Posted by Andrus Adamchik <an...@objectstyle.org>.
> But it would really help us a lot if we could get this to
> work, so maybe I can find the time later.


Yeah, would be cool if you get a chance to try it out with a HEAD build of either master or 3.1, and see which problems still remain.

Thanks for the information you shared so far.

Andrus

On Aug 6, 2014, at 12:35 PM, Erlend Birkenes <eb...@dataloy.com> wrote:

> Ok, I'll Jira it when I have a moment.
> 
> But I also just discovered that all the flattened attributes are null in
> the resolved objects (and in the DataRow), even though the data is present
> in the query result.
> 
> I was hoping there would be a quick fix to let me use joint prefetch, but
> this, together with the problem with combining joint and disjoint_by_id,
> makes me think that joint prefetch has more problems than I thought. I'll
> go back to using only disjoint_by_id and not dig any deeper into this, at
> least for now. But it would really help us a lot if we could get this to
> work, so maybe I can find the time later.
> 
> –
> Erlend <http://www.dataloy-systems.com>
> 
> 
> 2014-08-06 8:40 GMT+02:00 Andrus Adamchik <an...@objectstyle.org>:
> 
>> 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 <an...@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>
>>> 
>>> 
>> 
>> 


Re: Problem with joint prefetch and flattened attributes

Posted by Erlend Birkenes <eb...@dataloy.com>.
Ok, I'll Jira it when I have a moment.

But I also just discovered that all the flattened attributes are null in
the resolved objects (and in the DataRow), even though the data is present
in the query result.

I was hoping there would be a quick fix to let me use joint prefetch, but
this, together with the problem with combining joint and disjoint_by_id,
makes me think that joint prefetch has more problems than I thought. I'll
go back to using only disjoint_by_id and not dig any deeper into this, at
least for now. But it would really help us a lot if we could get this to
work, so maybe I can find the time later.

–
Erlend <http://www.dataloy-systems.com>


2014-08-06 8:40 GMT+02:00 Andrus Adamchik <an...@objectstyle.org>:

> 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 <an...@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>
> >
> >
>
>

Re: Problem with joint prefetch and flattened attributes

Posted by Andrus Adamchik <an...@objectstyle.org>.
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 <an...@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>
> 
> 


Re: Problem with joint prefetch and flattened attributes

Posted by Andrus Adamchik <an...@objectstyle.org>.
> 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>