| Summary: | A where clause on a sub-attribute (e.g. where emp.addr.name is not null) will change outer joins further up the hierarchy to inner joins | ||
|---|---|---|---|
| Product: | z_Archived | Reporter: | Martin Marinschek <martin.marinschek> |
| Component: | Eclipselink | Assignee: | Nobody - feel free to take it <nobody> |
| Status: | RESOLVED INVALID | QA Contact: | |
| Severity: | major | ||
| Priority: | P2 | CC: | jamesssss, tom.ware |
| Version: | unspecified | ||
| Target Milestone: | --- | ||
| Hardware: | PC | ||
| OS: | Windows XP | ||
| Whiteboard: | |||
Let me rephrase my example, cause in the given form it does not make much sense: a where clause including: (emp.addr.name = 'Max' or emp.addr.name is null) would not work. best regards, Martin I assume your query is something like select emp from Employee emp where emp.addr.name = 'Max' or emp.addr.name is null Can it be rewritten as something like select emp from Employee emp left join emp.addr a where a.name = 'Max' or a.name is null Hi Tom, it is more complex than this - goes over two hierarchies. I don't find a nice example with employee which makes sense and spans two hierarchies, I'll try it with a query from our domain: select wl from worklist wl left join wl.approval app left join app.approver apprv where (apprv.id is null or apprv.id = 'someId'); We of course have much more complex queries than this, spanning many more entities! Whenever I do something like this, outer joins are converted to inner joins. Query hints don't help. Also when ordering on something on the second hierarchy level, outer joins are converted to inner joins. All due to the code above. I really wonder why you guys are doing this? best regards, Martin Can you give me an example of some mappings that show the issue. I have tried with a fairly simple example with Project - 1-1 -> Employee - 1-1 -> Address and this query: select p from Project p left join p.teamLeader e left join e.address a where a.city = 'Ottawa' I still get the outer joins. FYI: the Expression.get() method is specifically designed to do a non-outer join. getAllowingNull() is the outer join equivalent (as you have mentioned) I will provide you with a test setup as soon as time permits - right now I am a bit in stress for a project delivery. It might as well be that it is not the where clause, but the order by which calls the get() and gets rid of the outer join. Setting target and priority. See the following page for the meanings of these fields: http://wiki.eclipse.org/EclipseLink/Development/Bugs/Guidelines Community: Please vote for this bug if it is important to you. Votes are one of the main criteria we use to determine which bugs to fix next. The issue is that the user is doing, Select e from Employee e left join e.address a where a.country = 'Canada' order by e.address.city EclipseLink is correct in using an inner join for address in this case, as e.address requires an inner join by the JPQL spec. The error is in the users JPQL, it should instead be, Select e from Employee e left join e.address a where a.country = 'Canada' order by a.city You must use the alias to ensure the outer join. The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink |
Build Identifier: 2.2.1 This behaviour effectively makes building complex queries spanning multiple tables (where some are optionally joined in) impossible. There is an easy fix to this - get rid of the result.doNotUseOuterJoin() statement below. I have tested the patch and it works for my environment. Note that in another issue, I also suggested to change super.get() to deriving the expression from the store, just as getAllowingNull does it. In any case, it would be interesting to know what the reason for this doNotUseOuterJoin() is - I don't see any reason from a generated SQL perspective? ObjectExpression: public Expression get(String attributeName, Vector arguments) { Expression operatorExpression = super.get(attributeName, arguments); if (operatorExpression != null) { return operatorExpression; } QueryKeyExpression result = derivedExpressionNamed(attributeName); result.doNotUseOuterJoin(); return result; } Reproducible: Always