dtoClass);
+ /**
+ * Return the underlying query as an UpdateQuery.
+ *
+ * Typically this is used with query beans to covert a query bean
+ * query into an UpdateQuery like the examples below.
+ *
+ *
+ * {@code
+ *
+ * int rowsUpdated = new QCustomer()
+ * .name.startsWith("Rob")
+ * .asUpdate()
+ * .set("active", false)
+ * .update();;
+ *
+ * }
+ *
+ * {@code
+ *
+ * int rowsUpdated = new QContact()
+ * .notes.note.startsWith("Make Inactive")
+ * .email.endsWith("@foo.com")
+ * .customer.id.equalTo(42)
+ * .asUpdate()
+ * .set("inactive", true)
+ * .setRaw("email = lower(email)")
+ * .update();
+ *
+ * }
+ */
+ UpdateQuery asUpdate();
+
/**
* Execute using "for update" clause which results in the DB locking the record.
*/
diff --git a/src/main/java/io/ebean/Query.java b/src/main/java/io/ebean/Query.java
index a1d34375d..eb4e0daa4 100644
--- a/src/main/java/io/ebean/Query.java
+++ b/src/main/java/io/ebean/Query.java
@@ -244,6 +244,38 @@ public interface Query {
*/
DtoQuery asDto(Class dtoClass);
+ /**
+ * Convert the query to a UpdateQuery.
+ *
+ * Typically this is used with query beans to covert a query bean
+ * query into an UpdateQuery like the examples below.
+ *
+ *
+ * {@code
+ *
+ * int rowsUpdated = new QCustomer()
+ * .name.startsWith("Rob")
+ * .asUpdate()
+ * .set("active", false)
+ * .update();;
+ *
+ * }
+ *
+ * {@code
+ *
+ * int rowsUpdated = new QContact()
+ * .notes.note.startsWith("Make Inactive")
+ * .email.endsWith("@foo.com")
+ * .customer.id.equalTo(42)
+ * .asUpdate()
+ * .set("inactive", true)
+ * .setRaw("email = lower(email)")
+ * .update();
+ *
+ * }
+ */
+ UpdateQuery asUpdate();
+
/**
* Cancel the query execution if supported by the underlying database and
* driver.
@@ -1329,7 +1361,6 @@ public interface Query {
* count:1 orderStatus:COMPLETE
*
* }
- *
*/
Query setCountDistinct(CountDistinctOrder orderBy);
diff --git a/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java b/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java
index 6a64b1b1b..85a8ffb26 100644
--- a/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java
+++ b/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java
@@ -18,6 +18,7 @@ import io.ebean.Pairs;
import io.ebean.Query;
import io.ebean.QueryIterator;
import io.ebean.Transaction;
+import io.ebean.UpdateQuery;
import io.ebean.Version;
import io.ebean.event.BeanQueryRequest;
import io.ebean.search.Match;
@@ -302,6 +303,11 @@ public class DefaultExpressionList implements SpiExpressionList {
return query.asDto(dtoClass);
}
+ @Override
+ public UpdateQuery asUpdate() {
+ return query.asUpdate();
+ }
+
@Override
public Query setIncludeSoftDeletes() {
return query.setIncludeSoftDeletes();
diff --git a/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java b/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java
index a4c2206db..e1c5a5a79 100644
--- a/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java
+++ b/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java
@@ -17,6 +17,7 @@ import io.ebean.Pairs;
import io.ebean.Query;
import io.ebean.QueryIterator;
import io.ebean.Transaction;
+import io.ebean.UpdateQuery;
import io.ebean.Version;
import io.ebean.event.BeanQueryRequest;
import io.ebean.search.Match;
@@ -349,6 +350,11 @@ class JunctionExpression implements SpiJunction, SpiExpression, Expression
return exprList.asDto(dtoClass);
}
+ @Override
+ public UpdateQuery asUpdate() {
+ return exprList.asUpdate();
+ }
+
@Override
public Query setIncludeSoftDeletes() {
return exprList.setIncludeSoftDeletes();
diff --git a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java
index 1f9056c3e..fc43615b3 100644
--- a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java
+++ b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java
@@ -22,6 +22,7 @@ import io.ebean.QueryIterator;
import io.ebean.QueryType;
import io.ebean.RawSql;
import io.ebean.Transaction;
+import io.ebean.UpdateQuery;
import io.ebean.Version;
import io.ebean.bean.CallStack;
import io.ebean.bean.ObjectGraphNode;
@@ -296,6 +297,11 @@ public class DefaultOrmQuery implements SpiQuery {
return server.findDto(dtoClass, this);
}
+ @Override
+ public UpdateQuery asUpdate() {
+ return new DefaultUpdateQuery<>(this);
+ }
+
@Override
public BeanDescriptor getBeanDescriptor() {
return beanDescriptor;
diff --git a/src/test/java/io/ebean/UpdateQueryTest.java b/src/test/java/io/ebean/UpdateQueryTest.java
index 545712bc6..5a5d9b698 100644
--- a/src/test/java/io/ebean/UpdateQueryTest.java
+++ b/src/test/java/io/ebean/UpdateQueryTest.java
@@ -75,6 +75,29 @@ public class UpdateQueryTest extends BaseTestCase {
assertThat(ormQueryMetrics.get(0).getLabel()).isEqualTo("updateAll");
}
+ @Test
+ public void query_asUpdate() {
+
+ ResetBasicData.reset();
+
+ LoggedSqlCollector.start();
+
+ int rows = server().find(Customer.class)
+ .where()
+ .gt("id", 1000)
+ .asUpdate()
+ .setRaw("status = status")
+ .setLabel("asUpdate")
+ .update();
+
+
+ List sql = LoggedSqlCollector.stop();
+ assertThat(sql).hasSize(1);
+ assertThat(rows).isEqualTo(0);
+
+ assertThat(sql.get(0)).contains("update o_customer set status = status where id > ?");
+ }
+
@Test
public void update_withTransactionBatch() {