Difference between revisions of "EclipseLink/UserGuide/JPA/Basic JPA Development/Querying/Query Casting"
(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...) |
m |
||
(2 intermediate revisions by the same user not shown) | |||
Line 7: | Line 7: | ||
=Query Casting= | =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. | + | 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 | + | The following examples show how to use EclipseLink to define queries on inheritance hierarchies with down casting to specific classes. |
− | == | + | == JPA 2.0 Type == |
− | + | Starting with JPA 2.0, it is possible to limit the results or a query to those of a specific subclass. For example, the expression framework provides <tt>Expression.type(Class)</tt>. | |
− | For example, the following | + | For example, the following query retrieves all the <tt>LargeProject</tt>s (subclass of <tt>Project</tt>) from <tt>Employee</tt>: |
select p from Employee e join e.projects p where type(p) = LargeProject | select p from Employee e join e.projects p where type(p) = LargeProject | ||
− | == JPQL | + | == Downcasting in JPQL == |
− | JPQL is | + | In JPQL, downcasting is accomplished in the FROM clause, using TREAT...AS in the JOIN clause. For example: |
select e from Employee e join TREAT(e.projects AS LargeProject) lp where lp.budget = value | select e from Employee e join TREAT(e.projects AS LargeProject) lp where lp.budget = value | ||
− | == Criteria API == | + | == JPA Criteria API == |
− | JPA Criteria API | + | Starting with JPA 2.0, the JPA Criteria API includes the casting operator <tt>Expression.as(type)</tt>. This expression does a simple cast that allows matching of types within the generics. |
− | + | EclipseLink extends the Criteria API to allow a cast using <tt>Expression.as(type)</tt>. The <tt>as</tt> method checks the hierarchy; and if <tt>type</tt> is a subclass of the type for the expression that is being called on, a cast is implemented. The following example shows a criteria query that does a cast: | |
− | + | ||
− | EclipseLink | + | |
Root<Employee> empRoot = cq1.from(getEntityManagerFactory().getMetamodel().entity(Employee.class)); | Root<Employee> empRoot = cq1.from(getEntityManagerFactory().getMetamodel().entity(Employee.class)); | ||
Line 38: | Line 36: | ||
cq1.where(qb1.equal(exp, new Integer(1000)) ); | cq1.where(qb1.equal(exp, new Integer(1000)) ); | ||
− | Calling a cast on a JOIN node | + | Calling a cast on a JOIN node permanently alters that node. For example, in the example above, after calling <tt>join.as(LargeProject.class)</tt>, the join refers to a <tt>LargeProject</tt>. |
== EclipseLink Expression Support for Downcast == | == EclipseLink Expression Support for Downcast == | ||
− | + | The EclipseLink <tt>Expression.as(Class)</tt> can also be used for downcasting, as shown in the following example: | |
ReadAllQuery raq = new ReadAllQuery(Employee.class); | ReadAllQuery raq = new ReadAllQuery(Employee.class); | ||
Line 49: | Line 47: | ||
List resultList = query.getResultList(); | List resultList = query.getResultList(); | ||
− | + | In the above query, <tt>Employee</tt> has an xToMany mapping to <tt>Project</tt>. <tt>LargeProject</tt> is a subclass of <tt>Project</tt>, and the <tt>budget</tt> attribute is contained on <tt>LargeProject</tt>. | |
− | * An exception | + | The behavior of using <tt>Expression.as(Class)</tt> is as follows: |
− | * Casts are only allowed on | + | |
− | * Casts use the same outer join settings as the ObjectExpression they modify | + | * An exception is 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 <tt>ObjectExpression</tt>s (<tt>QueryKeyExpression</tt> and <tt>ExpressionBuilder</tt>). The parent expression of a cast must be an <tt>ObjectExpression</tt>. | ||
+ | * Casts use the same outer join settings as the <tt>ObjectExpression</tt> 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. | * 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 | + | * Casting is not supported for <tt>TablePerClass</tt> inheritance |
− | * It is prudent to do a check for type in a query that does a cast. | + | * It is prudent to do a check for type in a query that does a cast. For example, 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" | ||
+ | |||
+ | if you want to enforce the type. | ||
+ | |||
+ | * EclipseLink automatically appends type information for cases where the cast results in a single type; but for classes in the middle of a hierarchy, no type information is appended to the SQL | ||
== Example SQL == | == Example SQL == | ||
Line 88: | Line 94: | ||
{{EclipseLink_JPA | {{EclipseLink_JPA | ||
|previous= [[EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/Query Hints|Query Hints]] | |previous= [[EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/Query Hints|Query Hints]] | ||
− | |next= [[EclipseLink/UserGuide/JPA/Basic_JPA_Development/ | + | |next= [[EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/Batch_Reading|Batch Reading]] |
|up= [[EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying|Querying]] | |up= [[EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying|Querying]] | ||
|version=2.2.0 DRAFT}} | |version=2.2.0 DRAFT}} |
Latest revision as of 14:27, 5 April 2011
EclipseLink JPA
EclipseLink | |
Website | |
Download | |
Community | |
Mailing List • Forums • IRC • mattermost | |
Issues | |
Open • Help Wanted • Bug 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 how to use EclipseLink to define queries on inheritance hierarchies with down casting to specific classes.
JPA 2.0 Type
Starting with JPA 2.0, it is possible to limit the results or a query to those of a specific subclass. For example, the expression framework provides Expression.type(Class).
For example, the following query retrieves all the LargeProjects (subclass of Project) from Employee:
select p from Employee e join e.projects p where type(p) = LargeProject
Downcasting in JPQL
In JPQL, downcasting is accomplished in the FROM clause, using TREAT...AS in the JOIN clause. For example:
select e from Employee e join TREAT(e.projects AS LargeProject) lp where lp.budget = value
JPA Criteria API
Starting with JPA 2.0, the JPA Criteria API includes the casting operator Expression.as(type). This expression does a simple cast that allows matching of types within the generics.
EclipseLink extends the Criteria API to allow a cast using Expression.as(type). The as method checks the hierarchy; and if type is a subclass of the type for the expression that is being called on, a cast is implemented. The following example shows a criteria query that does 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 permanently alters that node. For example, in the example above, after calling join.as(LargeProject.class), the join refers to a LargeProject.
EclipseLink Expression Support for Downcast
The EclipseLink Expression.as(Class) can also be used for downcasting, as shown in the following example:
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 the above query, Employee has an xToMany mapping to Project. LargeProject is a subclass of Project, and the budget attribute is contained on LargeProject.
The behavior of using Expression.as(Class) is as follows:
- An exception is 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. For example, 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"
if you want to enforce the type.
- EclipseLink automatically appends type information for cases where the cast results in a single type; but for classes in the middle of a hierarchy, no type information is 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]