Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

EclipseLink/UserGuide/JPA/Basic JPA Development/Querying/Query Casting

< EclipseLink‎ | UserGuide‎ | JPA‎ | Basic JPA Development‎ | Querying
Revision as of 12:46, 23 February 2011 by Ben.gelernter.oracle.com (Talk | contribs) (New page: {{EclipseLink_UserGuide |info=y |toc=n |eclipselink=y |eclipselinktype=JPA}} =Query Casting= Use query casting to query across attributes in subclasses when using JPA or ORM. This featu...)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

EclipseLink JPA

Eclipselink-logo.gif
EclipseLink
Website
Download
Community
Mailing ListForumsIRCmattermost
Issues
OpenHelp WantedBug Day
Contribute
Browse Source


Query Casting

Use query casting to query across attributes in subclasses when using JPA or ORM. This feature is available in JPQL, EclipseLink Expressions and Criteria API.

The following examples show on how to use EclipseLink to define queries on inheritance hierarchies with down casting to specific classes.

JPA2.0 Type

Extensions to the expression framework to limit the results to those of a specific subclass have already been implemented as part of the JPA 2.0 effort. Expression.type(Class) is available in the expression framework and equivalent functionality is available in JPQL.

For example, the following can be used to retrieve all the LargeProjects (Subclass of Project) from Employee.

select p from Employee e join e.projects p where type(p) = LargeProject 

JPQL Extensions to use Downcast

JPQL is extended to cast in the FROM clause. The format of this will use the keyword "TREAT" and be part of the join clause. The following is an example:

select e from Employee e join TREAT(e.projects AS LargeProject) lp where lp.budget = value

Criteria API

JPA Criteria API already provides a casting operator. It is Expression.as(type).

As it is defined by JPA 2.0, Expression.as(type) does a simple cast that allows matching of types within the generics.

EclipseLink 2.1 extends criteria API to allow a cast using Expression.as(type). The as method has been extended to check the hierarchy and if type is a subclass of the type for the expression that as is being called on a cast will be implemented. Here is a criteria query that will do a cast:

Root<Employee> empRoot = cq1.from(getEntityManagerFactory().getMetamodel().entity(Employee.class));
Join<Employee, Project> join = empRoot.join("projects");
Path exp = ((Path)join.as(LargeProject.class)).get("budget");
cq1.where(qb1.equal(exp, new Integer(1000)) );

Calling a cast on a JOIN node will permanently alter that node. i.e. In the example above, after calling join.as(LargeProject.class), join will refer to a LargeProject.

EclipseLink Expression Support for Downcast

We will implement Expression.as(Class). The following is an example of how one could use it:

       ReadAllQuery raq = new ReadAllQuery(Employee.class);
       Expression criteria = raq.getExpressionBuilder().anyOf("projects").as(LargeProject.class).get("budget").greaterThan(100);
       raq.setSelectionCriteria(criteria);
       List resultList = query.getResultList();

In this query Employee has a xToMany mapping to Project. LargeProject is a subclass of Project and the "budget" attribute is contained on LargeProject.

  • An exception will be thrown at query execution time if the class that is cast to is not a subclass of the class of the query key being cast.
  • Casts are only allowed on ObjectExpressions (QueryKeyExpression and ExpressionBuilder). The parent expression of a cast must be an ObjectExpression
  • Casts use the same outer join settings as the ObjectExpression they modify
  • Casts modify their parent expression. As a result, when using a cast with a parallel expression, you must use a new instance of the parent expression.
  • Casting is not supported for TablePerClass Inheritance
  • It is prudent to do a check for type in a query that does a cast.
    • The following select f from Foo f join cast(f.bars, BarSubclass) b where b.subclassAttribute = "value"
    • Should be written as: select f from Foo f join cast(f.bars, BarSubclass) b where type(b) = BarSubclass And b.subclassAttribute = "value" by users that wish to enforce the type.
    • EclipseLink will automatically append type information for cases where the cast results in a single type, but for classes in the middle of a hierarchy, no type information will not be appended to the SQL

Example SQL

The following query (which does not use query casting):

Select e from Employee e join e.projects project

produces the following sql:

SELECT <select list>
FROM CMP3_EMPLOYEE t1 LEFT OUTER JOIN CMP3_DEPT t0 ON (t0.ID = t1.DEPT_ID), CMP3_EMP_PROJ t4, CMP3_PROJECT t3, CMP3_SALARY t2 
WHERE ((t2.EMP_ID = t1.EMP_ID) AND ((t4.EMPLOYEES_EMP_ID = t1.EMP_ID) AND (t3.PROJ_ID = t4.projects_PROJ_ID)))


The following example shows a similar query, but with expanded select criteria:

Expression criteria = project.as(LargeProject.class).get("budget").greaterThan(100);
raq.setSelectionCriteria(criteria);

The above query produces the following SQL:

SELECT <select list> 
FROM CMP3_PROJECT t3 LEFT OUTER JOIN CMP3_LPROJECT t4 ON (t4.PROJ_ID = t3.PROJ_ID),CMP3_EMPLOYEE t1 LEFT OUTER JOIN CMP3_DEPT t0 ON (t0.ID = t1.DEPT_ID), CMP3_EMP_PROJ t5, CMP3_SALARY t2 
WHERE (((t4.BUDGET > ?) AND (t2.EMP_ID = t1.EMP_ID)) AND ((t5.EMPLOYEES_EMP_ID = t1.EMP_ID) AND (t3.PROJ_ID = t5.projects_PROJ_ID)))
bind => [100.0]

Eclipselink-logo.gif
Version: 2.2.0 DRAFT
Other versions...

Copyright © Eclipse Foundation, Inc. All Rights Reserved.