users@jpa-spec.java.net

[jpa-spec users] [jsr338-experts] Re: criteria API bulk update/delete

From: Linda DeMichiel <linda.demichiel_at_oracle.com>
Date: Fri, 10 Feb 2012 16:35:15 -0800

I've uploaded updated javadocs to the project Downloads area.
Please let me know if you find anything amiss.

-Linda


On 2/10/2012 1:46 PM, Linda DeMichiel wrote:
> Please see below...
>
> On 4/28/2011 1:10 PM, Linda DeMichiel wrote:
>>
>>
>> On 4/28/2011 4:04 AM, Emmanuel Bernard wrote:
>>> I haven't fired up my compiler nor spent too much time on it but could we get rid of the T param in
>>> CommonAbstractQuery (now CriteriaBase)? I can't seem to find what type-safety purpose it plays.
>>> What I do not like is that T in CommonAbstractQuery and T in AbstractQuery have different meanings (which smells like
>>> something we will regret later on).
>>>
>>
>> Yes -- I think this would send a clearer message.
>>
>>> We might be able to override from() in CriteriaDelete and CriteriaUpdate subclasses if you really want to bind them to
>>> a type
>>>
>
> To return to this specific point. We took this path back in April (and it is reflected in
> the current javadocs). However, while this worked when I tested it back then (jdk 1.6.0_25),
> it now results in compiler errors. The obvious fix is to move the from() methods in CommonAbstractQuery
> back down into AbstractQuery. At this point then, I think that CommonAbstractQuery serves
> little purpose, and my plan is to refactor to remove it. There should otherwise be no user-visible
> changes.
>
> -Linda
>
>
>>
>> That would make more sense with regard to the typing of the interfaces. The other
>> consequence would be to enforce a root over just that type.
>>
>> -Linda
>>
>>> class CriteriaDelete<T> extends CriteriaBase {
>>> Root<T> from(Class<T> entityClass);
>>> }
>>>
>>> Otherwise name wise, CriteriaBase, AbstractQuery (existing) CriteriaUpdate CriteriaDelete seem quite natural to me.
>>>
>>> Emmanuel
>>>
>>> On 28 mars 2011, at 20:53, Linda DeMichiel wrote:
>>>
>>>> One of the features of JPQL that the criteria API lacks is the
>>>> ability to issue bulk updates and deletes.
>>>>
>>>> Here's a cut at a strawman API for update and delete criteria queries.
>>>> There are a number of issues here that are in need of feedback.
>>>>
>>>> There are 3 new interfaces, which I've attached to the message:
>>>> UpdateQuery
>>>> DeleteQuery
>>>> CommonAbstractQuery
>>>>
>>>> I spent a long time mulling over whether to introduce a new type to
>>>> model the target (i.e. entity/table) of the update operation because
>>>> of the restricted semantics of bulk operation targets in SQL (i.e.,
>>>> single table, no derived joins in the UPDATE clause) or whether to
>>>> reuse Root. In the end, I decided to reuse Root, because of the
>>>> extensions that many databases provide to support joins. In this
>>>> case, the joined item is not itself updatable, but is used in the
>>>> expression of constraints or as a source of new values. However, we
>>>> will need to decide exactly what we state in terms of what is
>>>> "defined" vs "undefined" in the spec. Probably the most conservative
>>>> statement would be to state that the use of more than one root and/or
>>>> the use of joins is undefined.
>>>>
>>>> Another issue is whether UpdateQuery and DeleteQuery should exist in
>>>> any form of inheritance hierarchy to allow common information to be
>>>> factored out. I've done this in the interfaces attached to this
>>>> message. (The root of the factored hierarchy could certainly use a
>>>> better name, however.)
>>>>
>>>>
>>>> The CriteriaBuilder interface would be extended with methods
>>>> like:
>>>>
>>>> <T> UpdateQuery<T> createUpdateQuery(Class<T> targetEntity);
>>>> <T> UpdateQuery<T> createUpdateQuery(EntityType<T> targetEntity);
>>>> <T> DeleteQuery<T> createDeleteQuery(Class<T> targetEntity);
>>>> <T> DeleteQuery<T> createDeleteQuery(EntityType<T> targetEntity);
>>>>
>>>> And the EntityManager interface would be extended with methods like:
>>>>
>>>> public <T> TypedQuery createQuery(UpdateQuery<T> updateQuery)
>>>> public <T> TypedQuery createQuery(DeleteQuery<T> deleteQuery)
>>>>
>>>>
>>>> Example queries:
>>>>
>>>> // Simple Update
>>>>
>>>> UpdateQuery<Customer> q1 = cb.createUpdateQuery(Customer.class);
>>>> Root<Customer> c1 = q1.from(Customer.class);
>>>> q1.set(c1.get(Customer_.firstName), "Fred")
>>>> .set(c1.get(Customer_.lastName), "Jones")
>>>> .where(cb.equal(c1.get(Customer_.id), 1));
>>>>
>>>>
>>>> // Simple Delete
>>>>
>>>> DeleteQuery<Customer> q2 = cb.createDeleteQuery(Customer.class);
>>>> Root<Customer> c2 = q2.from(Customer.class);
>>>> q2.where(cb.equal(c2.get(Customer_.id), 5));
>>>>
>>>>
>>>> // Bulk Update
>>>>
>>>> UpdateQuery<Employee> q3 = cb.createUpdateQuery(Employee.class);
>>>> Root<Employee> e3 = q3.from(Employee.class);
>>>> q3.set(e3.get(Employee_.salary),
>>>> cb.prod(e3.get(Employee_.salary), 1.1).as(BigDecimal.class))
>>>> .where(cb.equal(e3.get(Employee_.dept).get(Department_.name), "Sales"));
>>>>
>>>>
>>>> // Bulk Delete
>>>>
>>>> DeleteQuery<Employee> q4 = cb.createDeleteQuery(Employee.class);
>>>> Root<Employee> e4 = q4.from(Employee.class);
>>>> q4.where(cb.equal(e4.type(), Exempt.class));
>>>>
>>>>
>>>> //Update query with multiple levels
>>>>
>>>> UpdateQuery<Customer> q5 = cb.createUpdateQuery(Customer.class);
>>>> Root<Customer> c5 = q5.from(Customer.class);
>>>> q5.set(c5.get(Customer_.address).get(Address_.city), "NewYork")
>>>> .set(c5.get(Customer_.address).get(Address_.state), "NewYork")
>>>> .where(cb.equal(c5.get(Customer_.id), 1));
>>>>
>>>>
>>>> Opinions, please.....
>>>>
>>>> thanks,
>>>>
>>>> -Linda
>>>> package javax.persistence.criteria;
>>>>
>>>> import javax.persistence.metamodel.SingularAttribute;
>>>>
>>>> public interface UpdateQuery<T> extends CommonAbstractQuery<T> {
>>>>
>>>> Root<T> getRoot();
>>>>
>>>> <Y> UpdateQuery<T> set(SingularAttribute<? super T, Y> attribute, Y value);
>>>>
>>>> <Y> UpdateQuery<T> set(SingularAttribute<? super T, Y> attribute, Expression<? extends Y> value);
>>>>
>>>> <Y> UpdateQuery<T> set(Path<Y> attribute, Y value);
>>>>
>>>> <Y> UpdateQuery<T> set(Path<Y> attribute, Expression<? extends Y> value);
>>>>
>>>> UpdateQuery<T> where(Expression<Boolean> restriction);
>>>>
>>>> UpdateQuery<T> where(Predicate... restrictions);
>>>>
>>>> }
>>>> package javax.persistence.criteria;
>>>>
>>>> public interface DeleteQuery<T> extends CommonAbstractQuery<T> {
>>>>
>>>> Root<T> getRoot();
>>>>
>>>> DeleteQuery<T> where(Expression<Boolean> restriction);
>>>>
>>>> DeleteQuery<T> where(Predicate... restrictions);
>>>>
>>>> }
>>>>
>>>> package javax.persistence.criteria;
>>>>
>>>> import java.util.List;
>>>> import java.util.Set;
>>>>
>>>> import javax.persistence.metamodel.EntityType;
>>>>
>>>> /**
>>>> * The <code>CommonAbstractQuery</code> interface defines functionality
>>>> * that is common to update and delete criteria operations ("update
>>>> * queries" and "delete queries" and to both top-level queries and
>>>> * subqueries.
>>>> * It is not intended to be used directly in query construction.
>>>> *
>>>> * <p> All queries must have:
>>>> * a set of root entities * <p> All queries may have:
>>>> * a conjunction of restrictions.
>>>> *
>>>> * @param <T> the type of the query
>>>> *
>>>> * @since Java Persistence 2.1
>>>> */
>>>> public interface CommonAbstractQuery<T> {
>>>>
>>>> /**
>>>> * Create and add a query root corresponding to the given entity,
>>>> * forming a cartesian product with any existing roots.
>>>> * @param entityClass the entity class
>>>> * @return query root corresponding to the given entity
>>>> */
>>>> <X> Root<X> from(Class<X> entityClass);
>>>>
>>>> /**
>>>> * Create and add a query root corresponding to the given entity,
>>>> * forming a cartesian product with any existing roots.
>>>> * @param entity metamodel entity representing the entity
>>>> * of type X
>>>> * @return query root corresponding to the given entity
>>>> */
>>>> <X> Root<X> from(EntityType<X> entity);
>>>>
>>>> /**
>>>> * Modify the query to restrict the query results according
>>>> * to the specified boolean expression.
>>>> * Replaces the previously added restriction(s), if any.
>>>> * @param restriction a simple or compound boolean expression
>>>> * @return the modified query
>>>> */ CommonAbstractQuery<T> where(Expression<Boolean> restriction);
>>>>
>>>> /**
>>>> * Modify the query to restrict the query results according * to the conjunction of the specified restriction
>>>> predicates.
>>>> * Replaces the previously added restriction(s), if any.
>>>> * If no restrictions are specified, any previously added
>>>> * restrictions are simply removed.
>>>> * @param restrictions zero or more restriction predicates
>>>> * @return the modified query
>>>> */
>>>> CommonAbstractQuery<T> where(Predicate... restrictions);
>>>>
>>>> /**
>>>> * Create a subquery of the query. * @param type the subquery result type
>>>> * @return subquery */
>>>> <U> Subquery<U> subquery(Class<U> type);
>>>>
>>>> /**
>>>> * Return the predicate that corresponds to the where clause
>>>> * restriction(s), or null if no restrictions have been
>>>> * specified.
>>>> * @return where clause predicate
>>>> */
>>>> Predicate getRestriction();
>>>>
>>>>
>>>> }
>>>>
>>>> package javax.persistence.criteria;
>>>>
>>>> import java.util.List;
>>>> import java.util.Set;
>>>>
>>>> import javax.persistence.metamodel.EntityType;
>>>>
>>>> /**
>>>> * The <code>AbstractQuery</code> interface defines functionality that is common
>>>> * to both top-level queries and subqueries.
>>>> * It is not intended to be used directly in query construction.
>>>> *
>>>> * <p> All queries must have:
>>>> * a set of root entities (which may in turn own joins).
>>>> * <p> All queries may have:
>>>> * a conjunction of restrictions.
>>>> *
>>>> * @param <T> the type of the result
>>>> *
>>>> * @since Java Persistence 2.0
>>>> */
>>>> public interface AbstractQuery<T> extends CommonAbstractQuery<T> {
>>>>
>>>> /**
>>>> * Modify the query to restrict the query results according
>>>> * to the specified boolean expression.
>>>> * Replaces the previously added restriction(s), if any.
>>>> * @param restriction a simple or compound boolean expression
>>>> * @return the modified query
>>>> */ AbstractQuery<T> where(Expression<Boolean> restriction);
>>>>
>>>> /**
>>>> * Modify the query to restrict the query results according * to the conjunction of the specified restriction
>>>> predicates.
>>>> * Replaces the previously added restriction(s), if any.
>>>> * If no restrictions are specified, any previously added
>>>> * restrictions are simply removed.
>>>> * @param restrictions zero or more restriction predicates
>>>> * @return the modified query
>>>> */
>>>> AbstractQuery<T> where(Predicate... restrictions);
>>>>
>>>> /**
>>>> * Specify the expressions that are used to form groups over
>>>> * the query results.
>>>> * Replaces the previous specified grouping expressions, if any.
>>>> * If no grouping expressions are specified, any previously * added grouping expressions are simply removed.
>>>> * @param grouping zero or more grouping expressions
>>>> * @return the modified query
>>>> */
>>>> AbstractQuery<T> groupBy(Expression<?>... grouping);
>>>>
>>>> /**
>>>> * Specify the expressions that are used to form groups over
>>>> * the query results.
>>>> * Replaces the previous specified grouping expressions, if any.
>>>> * If no grouping expressions are specified, any previously * added grouping expressions are simply removed.
>>>> * @param grouping list of zero or more grouping expressions
>>>> * @return the modified query
>>>> */
>>>> AbstractQuery<T> groupBy(List<Expression<?>> grouping);
>>>>
>>>> /**
>>>> * Specify a restriction over the groups of the query.
>>>> * Replaces the previous having restriction(s), if any.
>>>> * @param restriction a simple or compound boolean expression
>>>> * @return the modified query
>>>> */
>>>> AbstractQuery<T> having(Expression<Boolean> restriction);
>>>>
>>>> /**
>>>> * Specify restrictions over the groups of the query
>>>> * according the conjunction of the specified restriction * predicates.
>>>> * Replaces the previously having added restriction(s), if any.
>>>> * If no restrictions are specified, any previously added
>>>> * restrictions are simply removed.
>>>> * @param restrictions zero or more restriction predicates
>>>> * @return the modified query
>>>> */
>>>> AbstractQuery<T> having(Predicate... restrictions);
>>>>
>>>> /**
>>>> * Specify whether duplicate query results will be eliminated.
>>>> * A true value will cause duplicates to be eliminated.
>>>> * A false value will cause duplicates to be retained.
>>>> * If distinct has not been specified, duplicate results must
>>>> * be retained.
>>>> * @param distinct boolean value specifying whether duplicate
>>>> * results must be eliminated from the query result or
>>>> * whether they must be retained
>>>> * @return the modified query
>>>> */
>>>> AbstractQuery<T> distinct(boolean distinct);
>>>>
>>>> /**
>>>> * Return the query roots. These are the roots that have
>>>> * been defined for the <code>CriteriaQuery</code> or <code>Subquery</code> itself,
>>>> * including any subquery roots defined as a result of
>>>> * correlation. Returns empty set if no roots have been defined.
>>>> * Modifications to the set do not affect the query.
>>>> * @return the set of query roots
>>>> */ Set<Root<?>> getRoots();
>>>>
>>>> /**
>>>> * Return the selection of the query, or null if no selection
>>>> * has been set.
>>>> * @return selection item */
>>>> Selection<T> getSelection();
>>>>
>>>> /**
>>>> * Return a list of the grouping expressions. Returns empty
>>>> * list if no grouping expressions have been specified.
>>>> * Modifications to the list do not affect the query.
>>>> * @return the list of grouping expressions
>>>> */
>>>> List<Expression<?>> getGroupList();
>>>>
>>>> /**
>>>> * Return the predicate that corresponds to the restriction(s)
>>>> * over the grouping items, or null if no restrictions have * been specified.
>>>> * @return having clause predicate
>>>> */
>>>> Predicate getGroupRestriction();
>>>>
>>>> /**
>>>> * Return whether duplicate query results must be eliminated or
>>>> * retained.
>>>> * @return boolean indicating whether duplicate query results * must be eliminated
>>>> */
>>>> boolean isDistinct();
>>>>
>>>> /**
>>>> * Return the result type of the query or subquery. If a result
>>>> * type was specified as an argument to the
>>>> * <code>createQuery</code> or <code>subquery</code> method, that
>>>> * type will be returned. If the query was created using the
>>>> * <code>createTupleQuery</code> method, the result type is
>>>> * <code>Tuple</code>. Otherwise, the result type is
>>>> * <code>Object</code>.
>>>> * @return result type
>>>> */
>>>> Class<T> getResultType();
>>>> }
>>>
>>