RawSql よりも findNative が優先されます

findNative が RawSql よりも優先されることに注意してください。findNative は列とプロパティの自動マッピングを使用し、よりシンプルで使いやすいです。

RawSql は findNative の制限 のいずれかにアクセスした場合にのみ使用する必要があります。

RawSql - 解析されていない

解析されていない RawSql では、使用する SQL と列とプロパティのマッピングを明示的に指定します。SQL には ? の付きの位置パラメーターまたは :foo のような名前付きパラメーターを含めることができます。

RawSql インスタンスは変更できず、マルチスレッドでの使用に安全で、static final として宣言できます。

解析されていない RawSql では、WHERE 句と HAVING 句に追加の表現を指定することはできません。また、ORDER BY 句と LIMIT OFFSET 句を設定することもできません。それは 解析された RawSql でのみ行うことができます。

例 - 位置パラメーターを使用する場合
static final RawSql rawSql =
  RawSqlBuilder
    .unparsed("select r.id, r.name from o_customer r where r.id >= ? and r.name like ?")
    .columnMapping("r.id", "id")
    .columnMapping("r.name", "name")
    .create();

...

List<Customer> list = DB.find(Customer.class)
  .setRawSql(rawSql)
  .setParameter(42)
  .setParameter("R%")
  .findList();
例 - 名前 付きパラメーターを使用する場合
static final RawSql rawSql =
  RawSqlBuilder
    .unparsed("select r.id, r.name from o_customer r where r.id >= :a and r.name like :b")
    .columnMapping("r.id", "id")
    .columnMapping("r.name", "name")
    .create();

...

List<Customer> list = DB.find(Customer.class)
  .setRawSql(rawSql)
  .setParameter("a", 42)
  .setParameter("b", "R%")
  .findList();

RawSql - 解析済み

解析された RawSql では、WHERE 句と HAVING 句に動的に表現を追加したり、ORDER BY 句と LIMIT OFFSET 句を設定したりできます。

RawSql インスタンスは変更できず、マルチスレッドでの使用に安全で、static final として宣言できます。

// Use raw SQL with an aggregate function

String sql
= " select order_id, o.status, c.id, c.name, sum(d.order_qty*d.unit_price) as totalAmount"
+ " from orders o"
+ " join customer c on c.id = o.customer_id "
+ " join order_detail d on d.order_id = o.id "
+ " group by order_id, o.status ";

static final RawSql rawSql = RawSqlBuilder
  // let ebean parse the SQL so that it can add
  // expressions to the WHERE and HAVING clauses
  .parse(sql)
    // map resultSet columns to bean properties
    .columnMapping("order_id", "order.id")
    .columnMapping("o.status", "order.status")
    .columnMapping("c.id", "order.customer.id")
    .columnMapping("c.name", "order.customer.name")
    .create();

...

List<OrderAggregate> list = DB.find(OrderAggregate.class);
  query.setRawSql(rawSql)
  // add expressions to the WHERE and HAVING clauses
  .where().gt("order.id", 42)
  .having().gt("totalAmount", 20)
  .findList();

fetch

RawSql を使用する場合、fetchQuery を使用してオブジェクト グラフの他の部分をフェッチできます。つまり、「ルート」または「起点」クエリに RawSql を使用し、fetchQuery を使用してグラフの他の関連部分をフェッチできます。

// fetch additional parts of the object graph
// after the Raw SQL query is executed.

String sql
= " select order_id, sum(d.order_qty*d.unit_price) as totalAmount "
+ " from order_detail d"
+ " group by order_id ";

static final RawSql rawSql = RawSqlBuilder
  .parse(sql)
  .columnMapping("order_id", "order.id")
  .create();

...

Query<OrderAggregate> query = DB.find(OrderAggregate.class);
  query.setRawSql(rawSql)
    // get ebean to fetch parts of the order and customer
    // after the raw SQL query is executed
    .fetchQuery("order", "status,orderDate",new FetchConfig().query())
    .fetchQuery("order.customer", "name")
    .where().gt("order.id", 0)
    .having().gt("totalAmount", 20)
    .order().desc("totalAmount")
    .setMaxRows(10);

これは上記の例で使用されている OrderAggregate Bean です。

package com.avaje.tests.model.basic;

import javax.persistence.Entity;
import javax.persistence.OneToOne;

import com.avaje.ebean.annotation.Sql;

/**
* An example of an Aggregate object.
*
* Note the @Sql indicates to Ebean that this bean is not based on a table but
* instead uses RawSql.
*
*/
@Entity
@Sql
public class OrderAggregate {

  @OneToOne
  Order order;

  Double totalAmount;

  Double totalItems;

  public String toString() {
    return order.getId() + " totalAmount:" + totalAmount + " totalItems:" + totalItems;
  }

  public Order getOrder() {
    return order;
  }

  public void setOrder(Order order) {
    this.order = order;
  }

  public Double getTotalAmount() {
    return totalAmount;
  }

  public void setTotalAmount(Double totalAmount) {
    this.totalAmount = totalAmount;
  }

  public Double getTotalItems() {
    return totalItems;
  }

  public void setTotalItems(Double totalItems) {
    this.totalItems = totalItems;
  }
}

tableAliasMapping()

tableAliasMapping() は、クエリ結果の列をパスに基づいて関連オブジェクトに自動的にマップします。これはクエリ エイリアスを使用して行われます。これは個々の列を 1 つずつマップする必要がないようにする便利なメソッドです。

そのため、テスト ケースは次のようになります。

static final String rs =
  "select o.id, o.status, c.id, c.name, "+
  "       d.id, d.order_qty, p.id, p.name " +
  "from orders o join customer c on c.id = o.customer_id " +
  "join order_detail d on d.order_id = o.id " +
  "join product p on p.id = d.product_id " +
  "where o.id <= :maxOrderId and p.id = :productId "+
  "order by o.id, d.id asc";

static final RawSql rawSql = RawSqlBuilder.parse(rs)
    .tableAliasMapping("c", "customer")
    .tableAliasMapping("d", "details")
    .tableAliasMapping("p", "details.product")
    .create();

...

List<Order> ordersFromRaw = DB.find(Order.class)
    .setRawSql(rawSql)
    .setParameter("maxOrderId", 2)
    .setParameter("productId", 1)
    .findList();

次のように columnMapping を使用するのではなく

static final RawSql rawSql = RawSqlBuilder.parse(rs)
    .columnMapping("t0.id", "id")
    .columnMapping("t0.status", "status")
    .columnMapping("t1.id", "customer.id")
    .columnMapping("t1.name", "customer.name")
    .columnMapping("t2.id", "details.id")
    .columnMapping("t2.order_qty", "details.orderQty")
    .columnMapping("t3.id", "details.product.id")
    .columnMapping("t3.name", "details.product.name")
    .create();

名前付きクエリ

次の例のようになる生 SQL をプログラムで利用するか、Raw SQL と列マッピングを ebean-orm.xml ファイルに入れて、「名前付きクエリ」として参照します。database.createNamedQuery() を参照してください。