close

Summary of changes

A summary of changes needed in migrating to a later version of Ebean.

Upgrading to 17.x from 16.x

Query Changes

The most significant change in Ebean 17.x is the removal of EQL (Ebean Query Language). EQL was a string-based SQL-like query language. This has been removed in favor of more type-safe approaches.

Breaking Change: DB.createQuery(Class, eqlString)

16.x (old way - no longer works in 17.x):


// This NO LONGER WORKS in Ebean 17.x
String eql = "where customer.name like :custName and orderDate > :minOrderDate " +
             "order by id desc limit 50";

List<Order> orders = DB.createQuery(Order.class, eql)
  .setParameter("custName", "Rob%")
  .setParameter("minOrderDate", lastWeek)
  .findList();

17.x Solution 1: Query Beans (Recommended)


// Type-safe, IDE auto-completion, compile-time checking
List<Order> orders = new QOrder()
  .customer.name.contains("Rob")
  .orderDate.greaterThan(lastWeek)
  .orderBy().id.desc()
  .setMaxRows(50)
  .findList();

17.x Solution 2: Standard Query API


// Fluent API with string property names
List<Order> orders = DB.find(Order.class)
  .where()
    .contains("customer.name", "Rob")
    .gt("orderDate", lastWeek)
  .order().desc("id")
  .setMaxRows(50)
  .findList();

17.x Solution 3: Raw SQL (for complex queries)


// For complex database-specific SQL
List<Order> orders = DB.findNative(Order.class,
  "select * from or_order o join customer c on c.id = o.customer_id " +
  "where c.name like ? and o.order_date > ? " +
  "order by o.id desc limit 50")
  .setParameter(1, "Rob%")
  .setParameter(2, lastWeek)
  .findList();

Migration Decision Tree

Do you have an EQL query to migrate?

  • Simple predicates (where, order by, limit)?
    → Use Query Beans (recommended) or Standard Query API
  • Complex SQL (joins, subqueries, functions)?
    → Use Raw SQL / SqlQuery or DtoQuery
  • Named Queries (@NamedQuery)?
    → Migrate to Query Beans or Standard Query API called directly

EQL Feature Mapping

EQL Feature 17.x Replacement Example
where customer.name like :name Query Bean: .name.contains("Rob")
Query API: .contains("name", "Rob")
String pattern matching
where status = :status Query Bean: .status.eq(Status.NEW)
Query API: .eq("status", Status.NEW)
Equality check
order by id desc, name asc Query Bean: .orderBy().id.desc().name.asc()
Query API: .order().desc("id").asc("name")
Result ordering
limit 50 Query Bean: .setMaxRows(50)
Query API: .setMaxRows(50)
Limit results
fetch customer (name, email) Query Bean: .fetch("customer", "name, email")
Query API: .fetch("customer", "name, email")
Eager load specific properties

Complete EQL to Query Bean Migration Example

EQL (16.x):


String eql = "select (id, name, email) " +
             "fetch customer (id, name) " +
             "where status = :status and " +
             "customer.billingAddress.city like :city " +
             "order by id desc " +
             "limit 100";

List<Contact> contacts = DB.createQuery(Contact.class, eql)
  .setParameter("status", Status.ACTIVE)
  .setParameter("city", "Auckland%")
  .findList();

Query Beans (17.x - Recommended):


List<Contact> contacts = new QContact()
  .select("id, name, email")
  .fetch("customer", "id, name")
  .status.eq(Status.ACTIVE)
  .customer.billingAddress.city.contains("Auckland")
  .orderBy().id.desc()
  .setMaxRows(100)
  .findList();

Other Changes in 17.x

  • Named Queries: EQL syntax no longer actively developed (migrate to Query Beans)
  • Query Beans: Continue to be the recommended approach for type-safe queries
  • Standard Query API: Continues to be supported
  • SQL/SqlQuery: Continues to be the best option for complex database-specific queries

Programmatic Database configuration

Prefer explicit programmatic configuration via Database.builder() and injected Database instances. Older code may still use DatabaseConfig, DatabaseFactory, ServerConfig, EbeanServerFactory or rely on implicit bootstrap through DB.

Legacy style:


DatabaseConfig config = new DatabaseConfig();
config.loadFromProperties();
Database database = DatabaseFactory.create(config);

Preferred style:


Database database = Database.builder()
  .loadFromProperties()
  .build();

For named databases, call .name("mydb") before .loadFromProperties(). Prefer injecting the resulting Database rather than calling DB.byName("...").

Additional Resources

Upgrading to 12.x from 11.x

  • #1826 Removed @PrivateOwned, migrate to orphanRemoval=true attribute on @OneToMany
  • #1824 Stateless updates - Removed update deleteMissingChildren option, instead always use orphanRemoval behaviour change breaking-api

Upgrading to 11.x from 10.x

  • #1434 Remove deprecated API from EbeanServer - finder methods that take explicit transaction. Migrate to use ebeanServer.extended()
  • #1417 Breaking API - Remove PersistBatch.INSERT ... migrate to PersistBatch.ALL
  • #1424 Deprecate / Move ... finder methods that take explicit transaction to ExtendedServer API
  • new DbMigration(); -> DbMigration.create();
  • findUnique() -> findOne()
  • CacheMode.QUERY_ONLY -> GET
  • CacheMode.RECACHE -> PUT
  • io.ebean.Platform; -> io.ebean.annotation.Platform;
  • io.ebean.PersistBatch; -> io.ebean.annotation.PersistBatch;
  • io.ebean.TxType; -> io.ebean.annotation.TxType;
  • io.ebean.TxIsolation; -> io.ebean.annotation.TxIsolation;
  • Remove support for PropertyChangeListener from entity beans
  • Remove ServerConfig h2ProductionMode ... means for testing with h2 explicitly set ddlGenerate and ddlRun

Upgrading to 10.x from 9.x

  • Change package to io.ebean

  • Remove DbMigrationConfig.generateOnStart() ... migrate to offline generation

Upgrading to 9.x from 8.x

  • Query.includeSoftDeletes() -> setIncludeSoftDeletes()

Upgrading to 8.x from 7.x

  • (#682) Remove deprecated Model.Finder constructors that take Id type ... migrate to ones that don't

Upgrading to 7.x from 6.x

  • (#352) Remove deprecated API - ValuePair getValue1() getValue2() ... use getNewValue() getOldValue()
  • (#344) Remove deprecated annotation @ColumnHstore ... migrate to @DbHstore
  • (#343) Remove deprecated interface BeanFinder<T> ... migrate to BeanFindController
  • (#342) Remove deprecated method - JsonContext createJsonContext() ... migrate to json()
  • (#331) Remove deprecated method - EbeanServer.findVisit() ... migrate to findEach

Changes for: saveAll(), insertAll(), updateAll(), deleteAll()

  • (#341) Remove deprecated method - insert(Collection beans); ... migrate to insertAll()
  • (#340) Remove deprecated method - update(Collection beans) ... migrate to updateAll()
  • (#339) Remove deprecated method - save(Collection beans, Transaction transaction) ... migrate to saveAll()
  • (#339) Remove deprecated method - save(Collection beans, Transaction transaction) ... migrate to saveAll()
  • (#338) Remove deprecated method - save(Iterator it, Transaction transaction) ... please change to iterate yourself and save.
  • (#337) Remove deprecated method - delete(Class beanType, Collection ids) ... migrate to deleteAll()
  • (#336) Remove deprecated method - delete(Iterator it, Transaction transaction) ... migrate to deleteAll()
  • (#335) Remove deprecated method - delete(Collection beans) ... migrate to deleteAll()
  • (#334) Remove deprecated method - delete(Iterator it) ... migrate to deleteAll()
  • (#333) Remove deprecated method - save(Iterator it) ... change to iterate yourself and save()
  • (#332) Remove deprecated method - save(Collection beans) ... migrate to saveAll(beans)