diff --git a/src/main/java/io/ebean/ExpressionList.java b/src/main/java/io/ebean/ExpressionList.java index 5c7750cd3..2ac175d6a 100644 --- a/src/main/java/io/ebean/ExpressionList.java +++ b/src/main/java/io/ebean/ExpressionList.java @@ -1251,26 +1251,37 @@ public interface ExpressionList { /** * Add raw expression with a single parameter. *

- * The raw expression should contain a single ? at the location of the - * parameter. + * The raw expression should contain a single ? or ?1 + * at the location of the parameter. We use ?1 when binding a + * collection for an IN expression. *

- *

+ *

> * When properties in the clause are fully qualified as table-column names * then they are not translated. logical property name names (not fully * qualified) will still be translated to their physical name. *

*

- *

Example:

+ *

Examples:

*
{@code
    *
    *   // use a database function
    *   raw("add_days(orderDate, 10) < ?", someDate)
    *
+   *   raw("name like ?", "Rob%")
+   *
+   *   raw("name in (?1)", asList("Rob", "Fiona", "Jack"))
+   *
+   *   raw("name = any(?)", asList("Rob", "Fiona", "Jack"))
+   *
    * }
* - *

Subquery example:

+ *

Subquery examples:

*
{@code
    *
+   *   // Bind collection using ?1
+   *   .raw("id in (select c.id from o_customer c where c.name in (?1))", asList("Rob", "Fiona", "Jack"))
+   *
+   *   // Using Postgres ANY expression
    *   .raw("t0.customer_id in (select customer_id from customer_group where group_id = any(?::uuid[]))", groupIds)
    *
    * }
@@ -1280,14 +1291,25 @@ public interface ExpressionList { /** * Add raw expression with an array of parameters. *

- * The raw expression should contain the same number of ? as there are - * parameters. - *

+ * The raw expression should contain the same number of ? or ?1, ?2 ... bind parameters + * as there are values. We use ?1, ?2 etc when binding a collection for an IN expression. *

* When properties in the clause are fully qualified as table-column names * then they are not translated. logical property name names (not fully * qualified) will still be translated to their physical name. *

+ * + *

Examples:

+ *
{@code
+   *
+   *   raw("unitPrice > ? and product.id > ?", 2, 3)
+   *
+   *   raw("(status = ? or (orderDate < ? and shipDate is null) or customer.name like ?)",
+   *         Order.Status.APPROVED,
+   *         new Timestamp(System.currentTimeMillis()),
+   *         "Rob")
+   *
+   * }
*/ ExpressionList raw(String raw, Object... values); diff --git a/src/main/java/io/ebean/SqlQuery.java b/src/main/java/io/ebean/SqlQuery.java index be477ef96..8b5452ee7 100644 --- a/src/main/java/io/ebean/SqlQuery.java +++ b/src/main/java/io/ebean/SqlQuery.java @@ -224,12 +224,49 @@ public interface SqlQuery extends Serializable { * * } * + *

+ * When binding a collection of values into a IN expression we should use + * indexed parameters like ?1, ?2, ?3 etc rather than just ?. + *

+ * + *
{@code
+   *
+   *   String sql = "select c.id, c.name from customer c where c.name in (?1)";
+   *
+   *   List rows = DB.sqlQuery(sql)
+   *       .setParameter(asList("Rob", "Fiona", "Jack"))
+   *       .findList();
+   *
+   *
+   *   List rows = DB.sqlQuery(sql)
+   *       .setParameter(1, asList("Rob", "Fiona", "Jack"))
+   *       .findList();
+   * }
+ * * @param value The value to bind */ SqlQuery setParameter(Object value); /** * Bind the parameter by its index position (1 based like JDBC). + *

+ * When binding a collection of values into a IN expression we should use + * indexed parameters like ?1, ?2, ?3 etc rather than just ?. + *

+ * + *
{@code
+   *
+   *   String sql = "select c.id, c.name from customer c where c.name in (?1)";
+   *
+   *   List rows = DB.sqlQuery(sql)
+   *       .setParameter(asList("Rob", "Fiona", "Jack"))
+   *       .findList();
+   *
+   *
+   *   List rows = DB.sqlQuery(sql)
+   *       .setParameter(1, asList("Rob", "Fiona", "Jack"))
+   *       .findList();
+   * }
*/ SqlQuery setParameter(int position, Object value); diff --git a/src/main/java/io/ebean/SqlUpdate.java b/src/main/java/io/ebean/SqlUpdate.java index 2669ed224..927050d3f 100644 --- a/src/main/java/io/ebean/SqlUpdate.java +++ b/src/main/java/io/ebean/SqlUpdate.java @@ -5,18 +5,16 @@ package io.ebean; *

* Provides a simple way to execute raw SQL insert update or delete statements * without having to resort to JDBC. - *

*

* Supports the use of positioned or named parameters and can automatically * notify Ebean of the table modified so that Ebean can maintain its cache. - *

*

* Note that {@link #setAutoTableMod(boolean)} and * Ebean#externalModification(String, boolean, boolean, boolean)} can be to * notify Ebean of external changes and enable Ebean to maintain it's "L2" * server cache. - *

* + *

Positioned parameter example

*
{@code
  *
  *   // example using 'positioned' parameters
@@ -30,6 +28,7 @@ package io.ebean;
  *
  * }
* + *

Named parameter example

*
{@code
  *
  *   // example using 'named' parameters
@@ -45,8 +44,31 @@ package io.ebean;
  *   String msg = "There were " + rows + " rows updated";
  *
  * }
+ * + *

Index parameter examples (e.g. ?1, ?2, ?3 ...)

*

- *

Example: Using setNextParameter()

+ * We can use index parameters like ?1, ?2, ?3 etc when binding arrays/collections + * of values into an IN expression. + *

+ *
{@code
+ *
+ *   // Binding a list of 3 values (9991, 9992, 9993) into an IN expression
+ *
+ *   DB.sqlUpdate("delete from o_customer where name = ? and id in (?2)")
+ *     .setParameter(1, "Foo")
+ *     .setParameter(2, asList(9991, 9992, 9993))
+ *     .execute();
+ *
+ *   // note this effectively is the same as
+ *
+ *   DB.sqlUpdate("delete from o_customer where name = ? and id in (?2)")
+ *     .setParameter("Foo")
+ *     .setParameter(asList(9991, 9992, 9993))
+ *     .execute();
+ *
+ * }
+ * + *

Example: Using setParameter()

*
{@code
  *
  *  String sql = "insert into audit_log (id, description, modified_description) values (?,?,?)";
@@ -56,19 +78,19 @@ package io.ebean;
  *  try (Transaction txn = DB.beginTransaction()) {
  *    txn.setBatchMode(true);
  *
- *    insert.setNextParameter(10000);
- *    insert.setNextParameter("hello");
- *    insert.setNextParameter("rob");
+ *    insert.setParameter(10000);
+ *    insert.setParameter("hello");
+ *    insert.setParameter("rob");
  *    insert.execute();
  *
- *    insert.setNextParameter(10001);
- *    insert.setNextParameter("goodbye");
- *    insert.setNextParameter("rob");
+ *    insert.setParameter(10001);
+ *    insert.setParameter("goodbye");
+ *    insert.setParameter("rob");
  *    insert.execute();
  *
- *    insert.setNextParameter(10002);
- *    insert.setNextParameter("chow");
- *    insert.setNextParameter("bob");
+ *    insert.setParameter(10002);
+ *    insert.setParameter("chow");
+ *    insert.setParameter("bob");
  *    insert.execute();
  *
  *    txn.commit();
@@ -81,19 +103,19 @@ package io.ebean;
  *
  *   try (Transaction txn = DB.beginTransaction()) {
  *
- *     insert.setNextParameter(10000);
- *     insert.setNextParameter("hello");
- *     insert.setNextParameter("rob");
+ *     insert.setParameter(10000);
+ *     insert.setParameter("hello");
+ *     insert.setParameter("rob");
  *     insert.addBatch();
  *
- *     insert.setNextParameter(10001);
- *     insert.setNextParameter("goodbye");
- *     insert.setNextParameter("rob");
+ *     insert.setParameter(10001);
+ *     insert.setParameter("goodbye");
+ *     insert.setParameter("rob");
  *     insert.addBatch();
  *
- *     insert.setNextParameter(10002);
- *     insert.setNextParameter("chow");
- *     insert.setNextParameter("bob");
+ *     insert.setParameter(10002);
+ *     insert.setParameter("chow");
+ *     insert.setParameter("bob");
  *     insert.addBatch();
  *
  *     int[] rows = insert.executeBatch();
diff --git a/src/test/java/org/tests/query/TestWhereRawClause.java b/src/test/java/org/tests/query/TestWhereRawClause.java
index 41ebfc6f2..f90360371 100644
--- a/src/test/java/org/tests/query/TestWhereRawClause.java
+++ b/src/test/java/org/tests/query/TestWhereRawClause.java
@@ -1,6 +1,7 @@
 package org.tests.query;
 
 import io.ebean.BaseTestCase;
+import io.ebean.DB;
 import io.ebean.Ebean;
 import io.ebean.Expr;
 import io.ebean.Query;
@@ -57,7 +58,7 @@ public class TestWhereRawClause extends BaseTestCase {
 
     ResetBasicData.reset();
 
-    Query query = Ebean.find(Customer.class)
+    Query query = DB.find(Customer.class)
       .where()
       .raw("id in (select c.id from o_customer c where c.name in (?1))", asList("Rob", "Fiona", "Jack"))
       .query();