Save

Save will either insert or update the bean depending on its state.

Order order = new Order();
order.setOrderDate(new Date());
...
// insert the order
Ebean.save(order);

If the bean was fetched it will be updated...

Order order = Ebean.find(Order.class, 12);
order.setStatus("SHIPPED");
...
// update the order
Ebean.save(order);

Save and Delete will CASCADE based on the CascadeType specificed on the associated @OneToMany, @OneToOne etc annotation.

By default save and delete will not cascade so you need to specify a cascade type (such as the one on details below) for save() or delete() to cascade.

...
// the Entity bean with its Mapping Annotations
...
@Entity
@Table(name="or_order")
public class Order {

    ...
	// no cascading
    @ManyToOne
    Customer customer;

	// save and delete cascaded
    @OneToMany(cascade=CascadeType.ALL)
    List<OrderDetail> details;

	...

Note the @OneToMany(cascade=CascadeType.ALL) on the details property. This means save() and delete() will both casade from order to its order details.

...
// save the order ...  will cascade also saving the order details
Ebean.save(order);

Delete

Delete is very similar to save. Just call Ebean.delete();

...
Order order = Ebean.find(Order.class, 12);

// delete the order
// ... this will cascade also deleting the order details
// ... with either CascadeType.ALL or CascadeType.REMOVE
Ebean.delete(order);

Cascading

The mapping annotations @ManyToOne, @OneToMany, @OneToOne and @ManyToMany provide a cascade attribute which is used to control whether saves and deletes are cascaded.

The default is to not cascade a save or delete (as per JPA spec).

The example below shows the Order entity bean with its mapping annotations. If you save an Order the details will be saved as well but the associated customer will not be saved as there is no cascade atttribute and the default is to not cascade.

...
@Entity
@Table(name="or_order")
public class Order {
  ...
  // no cascading
  @ManyToOne
  Customer customer;

  // save and delete cascaded
  @OneToMany(cascade=CascadeType.ALL)
  List<OrderDetail> details;

Bulk updates

Update provides a way on issuing a insert, update or delete statement.

This is useful for updating or deleting multiple rows (or a single row) with a single statement (often described as a "bulk" update).

This is also useful if you want to perform an update or delete without having to execute a query first. This is a typical approach for performing an update in a stateless web application.

The statement can be provided in as raw DML with the table names and column names or in a 'logical' form where entity name is used in place of the table name and property names are used in place of column names.

// orm bulk delete use bean name and bean properties
server.createUpdate(OrderDetail.class, "delete from orderDetail").execute();

// sql bulk update uses table and column names
server.createSqlUpdate("delete from o_country").execute();
`

Bulk SQL updates

In similar fashion to SqlQuery you can specify a SQL INSERT, UPDATE or DELETE statement with named or positioned parameters.

String dml = "update b_bug set title=:title where id = :id";
SqlUpdate update = Ebean.createSqlUpdate(dml)
  .setParameter("title", "Updated Again")
  .setParameter("id", 1);
int rows = update.execute();

CallableSql

CallableSql provides a way to call a database stored procedure.

String sql = "{call sp_order_mod(?,?)}";
CallableSql cs = Ebean.createCallableSql(sql);
cs.setParameter(1, "turbo");
cs.registerOut(2, Types.INTEGER);
Ebean.execute(cs);

// read the out parameter
Integer returnValue = (Integer) cs.getObject(2);

You can extend CallableSql and you can also get the java.sql.Connection from a Transaction and use raw JDBC API to call a stored procedure.

Raw JDBC

You can't always predict when your application requirements can't be meet with the features in Ebean. It is nice you now you can easily use raw JDBC if and when you need to.

The java.sql.Connection object can be returned from a transaction, and with that you can perform any raw JDBC calls you like.

This may be useful for Savepoints, advanced Clob/Blob use or advanced stored procedure calls (if CallableSql doesn't do the business for you).

Transaction transaction = Ebean.beginTransaction();
try {
  Connection connection = transaction.getConnection();
  // use raw JDBC
  ...
  // assuming we updated the "o_shipping_details" table
  // inform Ebean so it can maintain it's 'L2' cache
  transaction.addModification("o_shipping_details",false,true,false);
  Ebean.commitTransaction();
} finally {
  Ebean.endTransaction();
}

The transaction.addModification() in the code above informs Ebean that your jdbc code updated the o_shipping_details table. Ebean uses this information to automatically manage its "L2" cache as well as maintain Lucene text indexes.

JDBC Batch

Ebean provides support for JDBC batch processing. Batch processing groups related SQL statements into a batch and submits them with one call to the database.

Batch settings can be configured through ebean.properties or through ServerConfig, and can be overridden per transaction.

You can set the batch mode for the entity being saved through setBatch() and for its child collections through setCascadeBatch().

...(under construction)... need to provide better guidance on how to determine batch mode, child batch mode, and batch size

Transaction transaction = ebeanServer.beginTransaction();
try {
  // turn of cascade persist
  transaction.setCascadePersist(false);

  // control the jdbc batch mode and size
  // transaction.setBatchMode(true); // equivalent to transaction.setBatch(PersistBatch.ALL);
  // transaction.setBatchMode(false); // equivalent to transaction.setBatch(PersistBatch.NONE);
  transaction.setBatch(PersistBatch.ALL); // PersistBatch: NONE, INSERT, ALL
  transaction.setCascadeBatch(PersistBatch.INSERT); // PersistBatch: NONE, INSERT, ALL
  transaction.setBatchSize(30);


  // for a large batch insert if you want to skip
  // getting the generated keys
  transaction.setBatchGetGeneratedKeys(false);

  // for batch processing via raw SQL you can inform
  // Ebean what tables were modified so that it can
  // clear the appropriate L2 caches
  String tableName = "o_customer";
  boolean inserts = true;
  boolean upates = true;
  boolean deletes = false;
  transaction.addModification(tableName, inserts, updates, deletes);

  ...
} finally {
  transaction.end();
}
example using @Transactional
@Transactional(batch = PersistBatch.ALL, batchOnCascade = PersistBatch.ALL, batchSize = 99)
  public void doWithBatchOptionsSet() {

    Transaction txn = Ebean.currentTransaction();
    assertEquals(PersistBatch.ALL, txn.getBatch());
    assertEquals(PersistBatch.ALL, txn.getBatchOnCascade());
    assertEquals(99, txn.getBatchSize());
}