Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 526546 - Expression onyOf does not work correct when conforming results in UnitOfWork
Summary: Expression onyOf does not work correct when conforming results in UnitOfWork
Status: RESOLVED FIXED
Alias: None
Product: z_Archived
Classification: Eclipse Foundation
Component: Eclipselink (show other bugs)
Version: unspecified   Edit
Hardware: PC Windows 7
: P3 blocker (vote)
Target Milestone: ---   Edit
Assignee: Nobody - feel free to take it CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-10-27 04:18 EDT by thorsten kruse CLA
Modified: 2022-06-09 10:34 EDT (History)
4 users (show)

See Also:


Attachments
Entitities and testcode (4.90 KB, text/plain)
2017-10-27 04:21 EDT, thorsten kruse CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description thorsten kruse CLA 2017-10-27 04:18:44 EDT
I have three entities Employee(name), Customer(name) and Contact(Emp, daysVisited, Cus).
Employee: Bob, Paul
Customer: CompA, CompB
Contacts: Con1 (Bob, 5 days, CompA), Con2 (Paul, 10 days, CompA), Con3 (Paul, 5 days, CompB)

Assume the contacts are already read. Using query expression language like this to query all employees visited customer CompA for 5 days:

ReadAllQuery raqEmp = new ReadAllQuery(Employee.class);
    raqEmp.conformResultsInUnitOfWork();
    raqEmp.setInMemoryQueryIndirectionPolicy(new InMemoryQueryIndirectionPolicy(InMemoryQueryIndirectionPolicy.SHOULD_TRIGGER_INDIRECTION));
    ExpressionBuilder ebEmp = new ExpressionBuilder();
    Expression exprAnyOf = ebEmp.anyOf("contacts");
    Expression exp = exprAnyOf.get("customer").equal(compA).and(exprAnyOf.get("daysVisted").equal(5));
    raqEmp.setSelectionCriteria(exp);

Paul is checked when conforming results in UnitOfWork: Paul has Con2 to customer CompA and Con3 with 5 days visited, so Paul is taken into the resultset. That is wrong, only Bob should be in the resultset as of Con1. If the contacts are not instantiated before, Paul ist not known to the cache.

Issue is present in eclipselink 2.7.0. Commented Code is attachted.
Comment 1 thorsten kruse CLA 2017-10-27 04:21:17 EDT
Created attachment 271209 [details]
Entitities and testcode
Comment 2 Lukas Jungmann CLA 2017-11-08 13:29:47 EST
Isn't:

raqEmp.setInMemoryQueryIndirectionPolicy(new InMemoryQueryIndirectionPolicy(InMemoryQueryIndirectionPolicy.SHOULD_THROW_INDIRECTION_EXCEPTION));

what you want?
Comment 3 thorsten kruse CLA 2017-11-10 06:09:06 EST
This is the default setting and it works because conforming the cache is bypassed. At UnitOfWork.scanForConformingInstances() the policy switches to SHOULD_IGNORE_EXCEPTION_RETURN_NOT_CONFORMED. There is a remark to bug 3568141.

With a little modification you see why I have to use SHOULD_TRIGGER_INDIRECTION: At the beginning assume the contacts are already read >>and for each contact daysVisited is set to 9.<< Do not commit to DB, go on using the UnitOfWork. Only when SHOULD_TRIGGER_INDIRECTION is used the resultSet of a following query for all employees visited customer CompA for 5 days counts to zero.
Comment 4 thorsten kruse CLA 2017-11-10 07:58:55 EST
To my mind the evaluation of the expression either does wrong or the expression is incorrect constructed.

In LogicalExpression.doesConform (the .and()) the expression is split into two parts: 1) exprAnyOf.get("customer").equal(compA) && 2) exprAnyOf.get("daysVisted").equal(5). If the expression is ok, both parts may not be evaluated independently.

If the expression is wrong, I have to create one like

builderA.anyOf("contacts").WHAT_HERE?(builderB.get("customer").equal(compA)and(builderB.(get("daysVisted").equal(5)))).

But how to? A Sub(Report)Query is not applicable because SHOULD_TRIGGER_INDIRECTION could not be set.
Comment 5 thorsten kruse CLA 2017-11-21 03:12:02 EST
Is someone out there who could help me?
Comment 6 Lukas Jungmann CLA 2018-02-22 14:03:21 EST
'equal' instead of 'and' is what seems to work as expected, so for given example use:

Expression exp = exprAnyOf.get("customer").equal(compA).equal(exprAnyOf.get("daysVisted").equal(5));
    raqEmp.setSelectionCriteria(exp);

instead of:
Expression exp = exprAnyOf.get("customer").equal(compA).and(exprAnyOf.get("daysVisted").equal(5));
    raqEmp.setSelectionCriteria(exp);
Comment 7 thorsten kruse CLA 2018-02-26 05:47:42 EST
An exception occurses as the constructed SQL-statement is invalid: Missing right  brace. It is the equal sign between the two terms: (t0.CUSTOMER_ID = ?) = (t0.DAYSVISTED = ?). 


[EL Warning]: 2018-02-26 11:33:28.88--UnitOfWork(1110014943)--Thread(Thread[main,5,main])--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLSyntaxErrorException: ORA-00907: Rechte Klammer fehlt

Error Code: 907
Call: SELECT DISTINCT t1.ID, t1.NAME FROM tke_Contact t0, TKE_EMPLOYEE t1 WHERE (((t0.CUSTOMER_ID = ?) = (t0.DAYSVISTED = ?)) AND (t0.EMPLOYEE_ID = t1.ID))
	bind => [2650, 5]
Query: ReadAllQuery(referenceClass=Employee sql="SELECT DISTINCT t1.ID, t1.NAME FROM tke_Contact t0, TKE_EMPLOYEE t1 WHERE (((t0.CUSTOMER_ID = ?) = (t0.DAYSVISTED = ?)) AND (t0.EMPLOYEE_ID = t1.ID))")
Exception in thread "main" Local Exception Stack: 
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLSyntaxErrorException: ORA-00907: Rechte Klammer fehlt

Error Code: 907
Call: SELECT DISTINCT t1.ID, t1.NAME FROM tke_Contact t0, TKE_EMPLOYEE t1 WHERE (((t0.CUSTOMER_ID = ?) = (t0.DAYSVISTED = ?)) AND (t0.EMPLOYEE_ID = t1.ID))
	bind => [2650, 5]
Query: ReadAllQuery(referenceClass=Employee sql="SELECT DISTINCT t1.ID, t1.NAME FROM tke_Contact t0, TKE_EMPLOYEE t1 WHERE (((t0.CUSTOMER_ID = ?) = (t0.DAYSVISTED = ?)) AND (t0.EMPLOYEE_ID = t1.ID))")
	at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:340)
	at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:682)
	at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:558)
	at org.eclipse.persistence.internal.sessions.AbstractSession.basicExecuteCall(AbstractSession.java:2002)
	at org.eclipse.persistence.sessions.server.ServerSession.executeCall(ServerSession.java:570)
	at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:242)
	at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:228)
	at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeSelectCall(DatasourceCallQueryMechanism.java:299)
	at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.selectAllRows(DatasourceCallQueryMechanism.java:694)
	at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.selectAllRowsFromTable(ExpressionQueryMechanism.java:2738)
	at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.selectAllRows(ExpressionQueryMechanism.java:2691)
	at org.eclipse.persistence.queries.ReadAllQuery.executeObjectLevelReadQuery(ReadAllQuery.java:495)
	at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1168)
	at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:899)
	at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1127)
	at org.eclipse.persistence.queries.ReadAllQuery.execute(ReadAllQuery.java:403)
	at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1215)
	at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2896)
	at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1804)
	at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1786)
	at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1737)
	at test.bug526546.Main_bug526546.doMain(Main_bug526546.java:116)
	at test.bug526546.Main_bug526546.main(Main_bug526546.java:186)
Caused by: java.sql.SQLSyntaxErrorException: ORA-00907: Rechte Klammer fehlt
Comment 8 Lukas Jungmann CLA 2018-02-26 05:56:47 EST
right, this does not work neither. The thing is that how it works is very likely by design and observed behaviour is as documented in https://wiki.eclipse.org/Introduction_to_EclipseLink_Expressions_(ELUG)#Using_EclipseLink_Expression_API_for_Joins

in particular see the note at that section, which says:

"Note: Calling anyOf once would result in a different outcome than if you call it twice. For example, if you query for an employee with a telephone area code of 613 and a number of 123-4599, you would use a single anyOf and a temporary variable. If you query for an employee, who has a telephone with an area code of 613, and who has a telephone with a number of 123-4599, you would call anyOf twice."
Comment 9 thorsten kruse CLA 2018-02-26 08:14:38 EST
I am sorry, I do not understand at all. The link is exactly the page I read when creating the code.

I want to query all employees visited customer CompA for 5 days. So I create the reference exprAnyOf:
Expression exprAnyOf = ebEmp.anyOf("contacts");
and use the reference twice:
Expression exp = exprAnyOf.get("customer").equal(compA).and(exprAnyOf.get("daysVisted").equal(5));

If I like to query all employees visited customer CompA and all employees visited a customer for 5 days, I would use:
ExpressionBuilder ebEmp = new ExpressionBuilder();
Expression exp = ebEmp.anyOf("contacts").equal(compA).and(ebEmp.anyOf("contacts").get("daysVisted").equal(5));
Comment 10 Lukas Jungmann CLA 2018-02-28 18:08:01 EST
(In reply to thorsten kruse from comment #4)
> If the expression is wrong, I have to create one like
> 
> builderA.anyOf("contacts").WHAT_HERE?(builderB.get("customer").
> equal(compA)and(builderB.(get("daysVisted").equal(5)))).

what about putting explicit join there? like ie:

ExpressionBuilder ebEmp = raqEmp.getExpressionBuilder()
ExpressionBuilder c = new ExpressionBuilder(Contact.class);
Expression exprAnyOf = ebEmp.anyOf("contacts");
Expression exp = (exprAnyOf.get("customer").equal(compA).and(exprAnyOf.get("daysVisted").equal(5)))
.and((c.get("customer").equal(compA)).and(c.get("employee").equal(ebEmp)));

...that seems to work on your sample
Comment 11 thorsten kruse CLA 2018-04-10 11:36:46 EDT
Well, yout suggestion seems to work. I do not test it at all, but with a first view everything works fine. Thanks a lot.

To my mind, this solution is a workaround. The documentaion linked and quoted at comment 8 shows the way I use the expressions and it should work. To manage my application, I would have to adjust and test about 250 pieces of code. Almost impossible.
Comment 12 Eclipse Genie CLA 2018-09-18 21:15:03 EDT
GitHub Pull Request 236 created by [lukasj]
https://github.com/eclipse-ee4j/eclipselink/pull/236
Comment 14 Sureshkumar Balakrishnannair CLA 2018-11-26 04:47:39 EST
Test Case (new link - Correction)

https://github.com/sureshbn/eclipselink/commit/9b393b4e3aac200f1f1baa33455b2937b2060210
Comment 15 Lukas Jungmann CLA 2018-11-26 04:51:09 EST
any chance you'll submit a pull request with that change?
Comment 16 Eclipse Genie CLA 2018-11-26 04:57:07 EST
GitHub Pull Request 293 created by [sureshbn]
https://github.com/eclipse-ee4j/eclipselink/pull/293
Comment 17 thorsten kruse CLA 2018-11-29 04:21:37 EST
The fix seems to be accepted, a UnitTest is created, great.
1) Will the fix be part of the next eclipselink release? 
2) When will the fix / the next release be available?

Regards, Thorsten
Comment 18 Lukas Jungmann CLA 2018-11-29 06:41:59 EST
(In reply to thorsten kruse from comment #17)
> The fix seems to be accepted, a UnitTest is created, great.
> 1) Will the fix be part of the next eclipselink release?

yes
 
> 2) When will the fix / the next release be available?

mid Dec or Jan; hopefully the former date

> 
> Regards, Thorsten
Comment 19 Eclipse Genie CLA 2018-12-18 06:39:22 EST
GitHub Pull Request 329 created by [lukasj]
https://github.com/eclipse-ee4j/eclipselink/pull/329
Comment 20 Eclipse Genie CLA 2018-12-18 06:40:41 EST
GitHub Pull Request 330 created by [lukasj]
https://github.com/eclipse-ee4j/eclipselink/pull/330
Comment 21 Lukas Jungmann CLA 2019-02-04 07:20:40 EST
this is already fixed in 2.6.6, 2.7.4 and master
Comment 22 Eclipse Webmaster CLA 2022-06-09 10:34:46 EDT
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink