All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.ebean.Database Maven / Gradle / Ivy

There is a newer version: 15.8.1
Show newest version
package io.ebean;

import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import io.ebean.annotation.Platform;
import io.ebean.annotation.TxIsolation;
import io.ebean.cache.ServerCacheManager;
import io.ebean.config.DatabaseConfig;
import io.ebean.meta.MetaInfoManager;
import io.ebean.plugin.Property;
import io.ebean.plugin.SpiServer;
import io.ebean.text.json.JsonContext;

import jakarta.persistence.OptimisticLockException;
import jakarta.persistence.PersistenceException;
import javax.sql.DataSource;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;

/**
 * Provides the API for fetching and saving beans to a particular database.
 *
 * 
Registration with the DB singleton
*

* When a Database instance is created it can be registered with the DB * singleton (see {@link DatabaseConfig#setRegister(boolean)}). The DB * singleton is essentially a map of Database's that have been registered * with it. *

* The Database can then be retrieved later via {@link DB#byName(String)}. * *

The 'default' Database
*

* One Database can be designated as the 'default' or 'primary' Database * (see {@link DatabaseConfig#setDefaultServer(boolean)}). Many methods on DB * such as {@link DB#find(Class)} etc are actually just a convenient way to * call methods on the 'default/primary' Database. * *

Constructing a Database
*

* Databases are constructed by the DatabaseFactory. They can be created * programmatically via {@link DatabaseFactory#create(DatabaseBuilder)} or they * can be automatically constructed on demand using configuration information in * the application.properties file. * *

Example: Get a Database
*
{@code
 *
 *   // Get access to the Human Resources Database
 *   Database hrDatabase = DB.byName("hr");
 *
 *
 *   // fetch contact 3 from the HR database
 *   Contact contact = hrDatabase.find(Contact.class, new Integer(3));
 *
 *   contact.setStatus("INACTIVE"); ...
 *
 *   // save the contact back to the HR database
 *   hrDatabase.save(contact);
 *
 * }
* *
Database vs DB API
*

* Database provides additional API compared with DB. For example, it * provides more control over the use of Transactions that is not available in * the DB API. * *

* External Transactions: If you wanted to use transactions created * externally to Ebean then Database provides additional methods where you * can explicitly pass a transaction (that can be created externally). * *

* Bypass ThreadLocal Mechanism: If you want to bypass the built-in * ThreadLocal transaction management you can use the createTransaction() * method. Example: a single thread requires more than one transaction. * * @see DB * @see DatabaseFactory * @see DatabaseConfig */ @NonNullApi public interface Database { /** * Return a new database builder. *

{@code
   *
   *   // build the 'default' database using configuration
   *   // from application.properties / application.yaml
   *
   *   Database db = Database.builder()
   *     .loadFromProperties()
   *     .build();
   *
   * }
*/ static DatabaseBuilder builder() { return new DatabaseConfig(); } /** * Shutdown the Database instance. */ void shutdown(); /** * Shutdown the Database instance programmatically. *

* This method is not normally required. Ebean registers a shutdown hook and shuts down cleanly. *

* If the under underlying DataSource is the Ebean implementation then you * also have the option of shutting down the DataSource and de-registering the * JDBC driver. * * @param shutdownDataSource if true then shutdown the underlying DataSource if it is the Ebean * DataSource implementation. * @param deregisterDriver if true then deregister the JDBC driver if it is the Ebean * DataSource implementation. */ void shutdown(boolean shutdownDataSource, boolean deregisterDriver); /** * Return AutoTune which is used to control the AutoTune service at runtime. */ AutoTune autoTune(); /** * Return the associated DataSource for this Database instance. */ DataSource dataSource(); /** * Return the associated read only DataSource for this Database instance (can be null). */ DataSource readOnlyDataSource(); /** * Return the name. This is used with {@link DB#byName(String)} to get a * Database that was registered with the DB singleton. */ String name(); /** * Return the ExpressionFactory for this database. */ ExpressionFactory expressionFactory(); /** * Return the MetaInfoManager which is used to get meta data from the Database * such as query execution statistics. */ MetaInfoManager metaInfo(); /** * Return the platform used for this database instance. *

* Note many platforms have multiple specific platform types so often we want to * get the base platform via {@link Platform#base()}. * *

{@code
   *
   *  Platform platform = database.platform().base();
   *  if (platform == Platform.MYSQL) {
   *    // do MySql specific function
   *  }
   *
   * }
* * @return platform for this database instance */ Platform platform(); /** * Return the extended API intended for use by plugins. */ SpiServer pluginApi(); /** * Return the BeanState for a given entity bean. *

* This will throw an IllegalArgumentException if the bean is not an enhanced entity bean. */ BeanState beanState(Object bean); /** * Return the value of the Id property for a given bean. */ Object beanId(Object bean); /** * Set the Id value onto the bean converting the type of the id value if necessary. *

* For example, if the id value passed in is a String but ought to be a Long or UUID etc * then it will automatically be converted. * * @param bean The entity bean to set the id value on. * @param id The id value to set. */ Object beanId(Object bean, Object id); /** * Return a map of the differences between two objects of the same type. *

* When null is passed in for b, then the 'OldValues' of a is used for the * difference comparison. */ Map diff(Object newBean, Object oldBean); /** * Create a new instance of T that is an EntityBean. *

* Useful if you use BeanPostConstructListeners or @PostConstruct Annotations. * In this case you should not use "new Bean...()". Making all bean constructors protected * could be a good idea here. */ T createEntityBean(Class type); /** * Create an Update query to perform a bulk update. *

*

{@code
   *
   *  int rows = database
   *      .update(Customer.class)
   *      .set("status", Customer.Status.ACTIVE)
   *      .set("updtime", new Timestamp(System.currentTimeMillis()))
   *      .where()
   *        .gt("id", 1000)
   *        .update();
   *
   * }
* * @param beanType The type of entity bean to update * @param The type of entity bean * @return The update query to use */ UpdateQuery update(Class beanType); /** * Create a query for an entity bean and synonym for {@link #find(Class)}. * * @see #find(Class) */ Query createQuery(Class beanType); /** * Create a query for a type of entity bean. *

* You can use the methods on the Query object to specify fetch paths, * predicates, order by, limits etc. *

* You then use findList(), findSet(), findMap() and findOne() to execute * the query and return the collection or bean. *

* Note that a query executed by {@link Query#findList()} * {@link Query#findSet()} etc will execute against the same Database from * which is was created. * *

{@code
   *
   *   // Find order 2 specifying explicitly the parts of the object graph to
   *   // eagerly fetch. In this case eagerly fetch the associated customer,
   *   // details and details.product.name
   *
   *   Order order = database.find(Order.class)
   *     .fetch("customer")
   *     .fetch("details")
   *     .fetch("detail.product", "name")
   *     .setId(2)
   *     .findOne();
   *
   *   // find some new orders ... with firstRow/maxRows
   *   List orders =
   *     database.find(Order.class)
   *       .where().eq("status", Order.Status.NEW)
   *       .setFirstRow(20)
   *       .setMaxRows(10)
   *       .findList();
   *
   * }
*/ Query find(Class beanType); /** * Create a query using native SQL. *

* The native SQL can contain named parameters or positioned parameters. * *

{@code
   *
   *   String sql = "select c.id, c.name from customer c where c.name like ? order by c.name";
   *
   *   Query query = database.findNative(Customer.class, sql);
   *   query.setParameter(1, "Rob%");
   *
   *   List customers = query.findList();
   *
   * }
* * @param beanType The type of entity bean to fetch * @param nativeSql The SQL that can contain named or positioned parameters * @return The query to set parameters and execute */ Query findNative(Class beanType, String nativeSql); /** * Return the next unique identity value for a given bean type. *

* This will only work when a IdGenerator is on the bean such as for beans * that use a DB sequence or UUID. *

* For DB's supporting getGeneratedKeys and sequences such as Oracle10 you do * not need to use this method generally. It is made available for more * complex cases where it is useful to get an ID prior to some processing. */ Object nextId(Class beanType); /** * Create a filter for sorting and filtering lists of entities locally without * going back to the database. *

* This produces and returns a new list with the sort and filters applied. *

* Refer to {@link Filter} for an example of its use. */ Filter filter(Class beanType); /** * Sort the list in memory using the sortByClause which can contain a comma delimited * list of property names and keywords asc, desc, nullsHigh and nullsLow. *

    *
  • asc - ascending order (which is the default)
  • *
  • desc - Descending order
  • *
  • nullsHigh - Treat null values as high/large values (which is the * default)
  • *
  • nullsLow- Treat null values as low/very small values
  • *
*

* If you leave off any keywords the defaults are ascending order and treating * nulls as high values. *

* Note that the sorting uses a Comparator and Collections.sort(); and does * not invoke a DB query. * *

{@code
   *
   *   // find orders and their customers
   *   List list = database.find(Order.class)
   *     .fetch("customer")
   *     .order("id")
   *     .findList();
   *
   *   // sort by customer name ascending, then by order shipDate
   *   // ... then by the order status descending
   *   database.sort(list, "customer.name, shipDate, status desc");
   *
   *   // sort by customer name descending (with nulls low)
   *   // ... then by the order id
   *   database.sort(list, "customer.name desc nullsLow, id");
   *
   * }
* * @param list the list of entity beans * @param sortByClause the properties to sort the list by */ void sort(List list, String sortByClause); /** * Create an orm update where you will supply the insert/update or delete * statement (rather than using a named one that is already defined using the * @NamedUpdates annotation). *

* The orm update differs from the sql update in that it you can use the bean * name and bean property names rather than table and column names. *

* An example: * *

{@code
   *
   *   // The bean name and properties - "topic","postCount" and "id"
   *
   *   // will be converted into their associated table and column names
   *   String updStatement = "update topic set postCount = :pc where id = :id";
   *
   *   Update update = database.createUpdate(Topic.class, updStatement);
   *
   *   update.set("pc", 9);
   *   update.set("id", 3);
   *
   *   int rows = update.execute();
   *   System.out.println("rows updated:" + rows);
   *
   * }
*/ Update createUpdate(Class beanType, String ormUpdate); /** * Create a Query for DTO beans. *

* DTO beans are just normal bean like classes with public constructor(s) and setters. * They do not need to be registered with DB before use. * * @param dtoType The type of the DTO bean the rows will be mapped into. * @param sql The SQL query to execute. * @param The type of the DTO bean. */ DtoQuery findDto(Class dtoType, String sql); /** * Look to execute a native sql query that does not return beans but instead * returns SqlRow or direct access to ResultSet. * *

* Refer to {@link DtoQuery} for native sql queries returning DTO beans. *

* Refer to {@link #findNative(Class, String)} for native sql queries returning entity beans. */ SqlQuery sqlQuery(String sql); /** * Look to execute a native sql insert update or delete statement. *

* Use this to execute a Insert Update or Delete statement. The statement will * be native to the database and contain database table and column names. * *

* See {@link SqlUpdate} for example usage. * * @return The SqlUpdate instance to set parameters and execute */ SqlUpdate sqlUpdate(String sql); /** * Create a CallableSql to execute a given stored procedure. */ CallableSql createCallableSql(String callableSql); /** * Register a TransactionCallback on the currently active transaction. *

* If there is no currently active transaction then a PersistenceException is thrown. * * @param transactionCallback The transaction callback to be registered with the current transaction. * @throws PersistenceException If there is no currently active transaction */ void register(TransactionCallback transactionCallback) throws PersistenceException; /** * Create a new transaction that is not held in TransactionThreadLocal. *

* You will want to do this if you want multiple Transactions in a single * thread or generally use transactions outside of the TransactionThreadLocal * management. */ Transaction createTransaction(); /** * Create a new transaction additionally specifying the isolation level. *

* Note that this transaction is NOT stored in a thread local. */ Transaction createTransaction(TxIsolation isolation); /** * Start a transaction with 'REQUIRED' semantics. *

* With REQUIRED semantics if an active transaction already exists that transaction will be used. *

* The transaction is stored in a ThreadLocal variable and typically you only * need to use the returned Transaction IF you wish to do things like * use batch mode, change the transaction isolation level, use savepoints or * log comments to the transaction log. *

* Example of using a transaction to span multiple calls to find(), save() etc. * *

Using try with resources

*
{@code
   *
   *   // start a transaction (stored in a ThreadLocal)
   *   try (Transaction txn = database.beginTransaction()) {
   *
   *     Order order = database.find(Order.class, 10);
   *     ...
   *     database.save(order);
   *
   *     txn.commit();
   *   }
   *
   * }
* *

Using try finally block

*
{@code
   *
   *   // start a transaction (stored in a ThreadLocal)
   *   Transaction txn = database.beginTransaction();
   *   try {
   * 	   Order order = database.find(Order.class,10);
   *
   *     database.save(order);
   *     txn.commit();
   *
   *   } finally {
   *     txn.end();
   *   }
   * }
* *

Transaction options

*
{@code
   *
   *   try (Transaction txn = database.beginTransaction()) {
   *
   *     // explicitly turn on/off JDBC batch use
   *     txn.setBatchMode(true);
   *     txn.setBatchSize(50);
   *
   *     // control flushing when mixing save and queries
   *     txn.setBatchFlushOnQuery(false);
   *
   *     // turn off persist cascade if needed
   *     txn.setPersistCascade(false);
   *
   *     // for large batch insert processing when we do not
   *     // ... need the generatedKeys, don't get them
   *     txn.setBatchGetGeneratedKeys(false);
   *
   *     // explicitly flush the JDBC batch buffer
   *     txn.flush();
   *
   *     ...
   *
   *     txn.commit();
   *   }
   *
   * }
*

* If you want to externalise the transaction management then you use * createTransaction() and pass the transaction around to the various methods on * Database yourself. */ Transaction beginTransaction(); /** * Start a transaction additionally specifying the isolation level. */ Transaction beginTransaction(TxIsolation isolation); /** * Start a transaction typically specifying REQUIRES_NEW or REQUIRED semantics. *

* Note that this provides an try finally alternative to using {@link #executeCall(TxScope, Callable)} or * {@link #execute(TxScope, Runnable)}. * *

REQUIRES_NEW example:

*
{@code
   * // Start a new transaction. If there is a current transaction
   * // suspend it until this transaction ends
   * try (Transaction txn = database.beginTransaction(TxScope.requiresNew())) {
   *
   *   ...
   *
   *   // commit the transaction
   *   txn.commit();
   *
   *   // At end this transaction will:
   *   //  A) will rollback transaction if it has not been committed
   *   //  B) will restore a previously suspended transaction
   * }
   *
   * }
*

*

REQUIRED example:

*
{@code
   *
   * // start a new transaction if there is not a current transaction
   * try (Transaction txn = database.beginTransaction(TxScope.required())) {
   *
   *   ...
   *
   *   // commit the transaction if it was created or
   *   // do nothing if there was already a current transaction
   *   txn.commit();
   * }
   *
   * }
*/ Transaction beginTransaction(TxScope scope); /** * Returns the current transaction or null if there is no current transaction in scope. */ Transaction currentTransaction(); /** * Flush the JDBC batch on the current transaction. *

* This only is useful when JDBC batch is used. Flush occurs automatically when the * transaction commits or batch size is reached. This manually flushes the JDBC batch * buffer. *

* This is the same as currentTransaction().flush(). */ void flush(); /** * Refresh the values of a bean. *

* Note that this resets OneToMany and ManyToMany properties so that if they * are accessed a lazy load will refresh the many property. */ void refresh(Object bean); /** * Refresh a many property of an entity bean. * * @param bean the entity bean containing the 'many' property * @param propertyName the 'many' property to be refreshed */ void refreshMany(Object bean, String propertyName); /** * Find a bean using its unique id. *

*

{@code
   *   // Fetch order 1
   *   Order order = database.find(Order.class, 1);
   * }
* *

* If you want more control over the query then you can use createQuery() and * Query.findOne(); * *

{@code
   *   // ... additionally fetching customer, customer shipping address,
   *   // order details, and the product associated with each order detail.
   *   // note: only product id and name is fetch (its a "partial object").
   *   // note: all other objects use "*" and have all their properties fetched.
   *
   *   Query query = database.find(Order.class)
   *     .setId(1)
   *     .fetch("customer")
   *     .fetch("customer.shippingAddress")
   *     .fetch("details")
   *     .query();
   *
   *   // fetch associated products but only fetch their product id and name
   *   query.fetch("details.product", "name");
   *
   *
   *   Order order = query.findOne();
   *
   *   // traverse the object graph...
   *
   *   Customer customer = order.getCustomer();
   *   Address shippingAddress = customer.getShippingAddress();
   *   List details = order.getDetails();
   *   OrderDetail detail0 = details.get(0);
   *   Product product = detail0.getProduct();
   *   String productName = product.getName();
   *
   * }
* * @param beanType the type of entity bean to fetch * @param id the id value */ @Nullable T find(Class beanType, Object id); /** * Get a reference object. *

* This will not perform a query against the database unless some property other * that the id property is accessed. *

* It is most commonly used to set a 'foreign key' on another bean like: * *

{@code
   *
   *   Product product = database.getReference(Product.class, 1);
   *
   *   OrderDetail orderDetail = new OrderDetail();
   *   // set the product 'foreign key'
   *   orderDetail.setProduct(product);
   *   orderDetail.setQuantity(42);
   *   ...
   *
   *   database.save(orderDetail);
   *
   *
   * }
*

*

Lazy loading characteristics

*
{@code
   *
   *   Product product = database.getReference(Product.class, 1);
   *
   *   // You can get the id without causing a fetch/lazy load
   *   Long productId = product.getId();
   *
   *   // If you try to get any other property a fetch/lazy loading will occur
   *   // This will cause a query to execute...
   *   String name = product.getName();
   *
   * }
* * @param beanType the type of entity bean * @param id the id value */ T reference(Class beanType, Object id); /** * Return the extended API for Database. *

* The extended API has the options for executing queries that take an explicit * transaction as an argument. *

* Typically, we only need to use the extended API when we do NOT want to use the * usual ThreadLocal based mechanism to obtain the current transaction but instead * supply the transaction explicitly. */ ExtendedServer extended(); /** * Either Insert or Update the bean depending on its state. *

* If there is no current transaction one will be created and committed for * you automatically. *

* Save can cascade along relationships. For this to happen you need to * specify a cascade of CascadeType.ALL or CascadeType.PERSIST on the * OneToMany, OneToOne or ManyToMany annotation. *

* In this example below the details property has a CascadeType.ALL set so * saving an order will also save all its details. * *

{@code
   *   public class Order { ...
   *
   *     @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
   *     List details;
   *     ...
   *   }
   * }
*

* When a save cascades via a OneToMany or ManyToMany Ebean will automatically * set the 'parent' object to the 'detail' object. In the example below in * saving the order and cascade saving the order details the 'parent' order * will be set against each order detail when it is saved. */ void save(Object bean) throws OptimisticLockException; /** * Save all the beans in the collection. */ int saveAll(Collection beans) throws OptimisticLockException; /** * Save all the beans. */ int saveAll(Object... beans) throws OptimisticLockException; /** * Delete the bean. *

* This will return true if the bean was deleted successfully or JDBC batch is being used. *

* If there is no current transaction one will be created and committed for * you automatically. *

* If the Bean does not have a version property (or loaded version property) and * the bean does not exist then this returns false indicating that nothing was * deleted. Note that, if JDBC batch mode is used then this always returns true. */ boolean delete(Object bean) throws OptimisticLockException; /** * Delete the bean with an explicit transaction. *

* This will return true if the bean was deleted successfully or JDBC batch is being used. *

* If the Bean does not have a version property (or loaded version property) and * the bean does not exist then this returns false indicating that nothing was * deleted. However, if JDBC batch mode is used then this always returns true. */ boolean delete(Object bean, Transaction transaction) throws OptimisticLockException; /** * Delete a bean permanently without soft delete. */ boolean deletePermanent(Object bean) throws OptimisticLockException; /** * Delete a bean permanently without soft delete using an explicit transaction. */ boolean deletePermanent(Object bean, Transaction transaction) throws OptimisticLockException; /** * Delete all the beans in the collection permanently without soft delete. */ int deleteAllPermanent(Collection beans) throws OptimisticLockException; /** * Delete all the beans in the collection permanently without soft delete using an explicit transaction. */ int deleteAllPermanent(Collection beans, Transaction transaction) throws OptimisticLockException; /** * Delete the bean given its type and id. */ int delete(Class beanType, Object id); /** * Delete the bean given its type and id with an explicit transaction. */ int delete(Class beanType, Object id, Transaction transaction); /** * Delete permanent given the bean type and id. */ int deletePermanent(Class beanType, Object id); /** * Delete permanent given the bean type and id with an explicit transaction. */ int deletePermanent(Class beanType, Object id, Transaction transaction); /** * Delete all the beans in the collection. */ int deleteAll(Collection beans) throws OptimisticLockException; /** * Delete all the beans in the collection using an explicit transaction. */ int deleteAll(Collection beans, Transaction transaction) throws OptimisticLockException; /** * Delete several beans given their type and id values. */ int deleteAll(Class beanType, Collection ids); /** * Delete several beans given their type and id values with an explicit transaction. */ int deleteAll(Class beanType, Collection ids, Transaction transaction); /** * Delete permanent for several beans given their type and id values. */ int deleteAllPermanent(Class beanType, Collection ids); /** * Delete permanent for several beans given their type and id values with an explicit transaction. */ int deleteAllPermanent(Class beanType, Collection ids, Transaction transaction); /** * Execute a Sql Update Delete or Insert statement. This returns the number of * rows that where updated, deleted or inserted. If is executed in batch then * this returns -1. You can get the actual rowCount after commit() from * updateSql.getRowCount(). *

* If you wish to execute a Sql Select natively then you should use the * SqlQuery object or DtoQuery. *

* Note that the table modification information is automatically deduced and * you do not need to call the DB.externalModification() method when you * use this method. *

* Example: * *

{@code
   *
   *   // example that uses 'named' parameters
   *   String s = "UPDATE f_topic set post_count = :count where id = :id"
   *
   *   SqlUpdate update = database.createSqlUpdate(s);
   *
   *   update.setParameter("id", 1);
   *   update.setParameter("count", 50);
   *
   *   int modifiedCount = database.execute(update);
   *
   *   String msg = "There where " + modifiedCount + "rows updated";
   *
   * }
* * @param sqlUpdate the update sql potentially with bind values * @return the number of rows updated or deleted. -1 if executed in batch. * @see CallableSql */ int execute(SqlUpdate sqlUpdate); /** * Execute a ORM insert update or delete statement using the current * transaction. *

* This returns the number of rows that where inserted, updated or deleted. */ int execute(Update update); /** * Execute a ORM insert update or delete statement with an explicit * transaction. */ int execute(Update update, Transaction transaction); /** * For making calls to stored procedures. *

* Example: * *

{@code
   *
   *   String sql = "{call sp_order_modify(?,?,?)}";
   *
   *   CallableSql cs = database.createCallableSql(sql);
   *   cs.setParameter(1, 27);
   *   cs.setParameter(2, "SHIPPED");
   *   cs.registerOut(3, Types.INTEGER);
   *   cs.execute();
   *
   *   // read the out parameter
   *   Integer returnValue = (Integer) cs.getObject(3);
   *
   * }
*/ int execute(CallableSql callableSql); /** * Inform Ebean that tables have been modified externally. These could be the * result of from calling a stored procedure, other JDBC calls or external * programs including other frameworks. *

* If you use database.execute(UpdateSql) then the table modification information * is automatically deduced and you do not need to call this method yourself. *

* This information is used to invalidate objects out of the cache and * potentially text indexes. This information is also automatically broadcast * across the cluster. *

* If there is a transaction then this information is placed into the current * transactions event information. When the transaction is committed this * information is registered (with the transaction manager). If this * transaction is rolled back then none of the transaction event information * registers including the information you put in via this method. *

* If there is NO current transaction when you call this method then this * information is registered immediately (with the transaction manager). * * @param tableName the name of the table that was modified * @param inserted true if rows where inserted into the table * @param updated true if rows on the table where updated * @param deleted true if rows on the table where deleted */ void externalModification(String tableName, boolean inserted, boolean updated, boolean deleted); /** * Find a entity bean with an explicit transaction. * * @param the type of entity bean to find * @param beanType the type of entity bean to find * @param id the bean id value * @param transaction the transaction to use (can be null) */ @Nullable T find(Class beanType, Object id, Transaction transaction); /** * Insert or update a bean with an explicit transaction. */ void save(Object bean, Transaction transaction) throws OptimisticLockException; /** * Save all the beans in the collection with an explicit transaction. */ int saveAll(Collection beans, Transaction transaction) throws OptimisticLockException; /** * This method checks the uniqueness of a bean. I.e. if the save will work. It will return the * properties that violates an unique / primary key. This may be done in an UI save action to * validate if the user has entered correct values. *

* Note: This method queries the DB for uniqueness of all indices, so do not use it in a batch update. *

* Note: This checks only the root bean! *

*

{@code
   *   // there is a unique constraint on title
   *
   *   Document doc = new Document();
   *   doc.setTitle("One flew over the cuckoo's nest");
   *   doc.setBody("clashes with doc1");
   *
   *   Set properties = DB.checkUniqueness(doc);
   *
   *   if (properties.isEmpty()) {
   *     // it is unique ... carry on
   *
   *   } else {
   *     // build a user friendly message
   *     // to return message back to user
   *
   *     String uniqueProperties = properties.toString();
   *
   *     StringBuilder msg = new StringBuilder();
   *
   *     properties.forEach((it)-> {
   *       Object propertyValue = it.getVal(doc);
   *       String propertyName = it.getName();
   *       msg.append(" property["+propertyName+"] value["+propertyValue+"]");
   *     });
   *
   *     // uniqueProperties > [title]
   *     //       custom msg > property[title] value[One flew over the cuckoo's nest]
   *
   *   }
   *
   * }
* * @param bean The entity bean to check uniqueness on * @return a set of Properties if constraint validation was detected or empty list. */ Set checkUniqueness(Object bean); /** * Same as {@link #checkUniqueness(Object)}. but with given transaction. */ Set checkUniqueness(Object bean, Transaction transaction); /** * Marks the entity bean as dirty. *

* This is used so that when a bean that is otherwise unmodified is updated the version * property is updated. *

* An unmodified bean that is saved or updated is normally skipped and this marks the bean as * dirty so that it is not skipped. *

*

{@code
   *   Customer customer = database.find(Customer, id);
   *
   *   // mark the bean as dirty so that a save() or update() will
   *   // increment the version property
   *   database.markAsDirty(customer);
   *   database.save(customer);
   *
   * }
*/ void markAsDirty(Object bean); /** * Saves the bean using an update. If you know you are updating a bean then it is preferable to * use this update() method rather than save(). *

* Stateless updates: Note that the bean does not have to be previously fetched to call * update().You can create a new instance and set some of its properties programmatically for via * JSON/XML marshalling etc. This is described as a 'stateless update'. *

* Optimistic Locking: Note that if the version property is not set when update() is * called then no optimistic locking is performed (internally ConcurrencyMode.NONE is used). * *

{@code
   *
   *   // A 'stateless update' example
   *   Customer customer = new Customer();
   *   customer.setId(7);
   *   customer.setName("ModifiedNameNoOCC");
   *   database.update(customer);
   *
   * }
*/ void update(Object bean) throws OptimisticLockException; /** * Update a bean additionally specifying a transaction. */ void update(Object bean, Transaction transaction) throws OptimisticLockException; /** * Update a collection of beans. If there is no current transaction one is created and used to * update all the beans in the collection. */ void updateAll(Collection beans) throws OptimisticLockException; /** * Update a collection of beans with an explicit transaction. */ void updateAll(Collection beans, Transaction transaction) throws OptimisticLockException; /** * Merge the bean using the default merge options (no paths specified, default delete). * * @param bean The bean to merge */ void merge(Object bean); /** * Merge the bean using the given merge options. * * @param bean The bean to merge * @param options The options to control the merge */ void merge(Object bean, MergeOptions options); /** * Merge the bean using the given merge options and a transaction. * * @param bean The bean to merge * @param options The options to control the merge */ void merge(Object bean, MergeOptions options, Transaction transaction); /** * Insert the bean. *

* Compared to save() this forces bean to perform an insert rather than trying to decide * based on the bean state. As such this is useful when you fetch beans from one database * and want to insert them into another database (and you want to explicitly insert them). */ void insert(Object bean); /** * Insert the bean with options (ON CONFLICT DO UPDATE | DO NOTHING). *

* Currently, this is limited to use with Postgres only, *

* When using this ebean will look to determine the unique columns by looking at * the mapping like {@code @Column(unique=true} and {@code @Index(unique=true}. */ void insert(Object bean, InsertOptions insertOptions); /** * Insert the bean with a transaction. */ void insert(Object bean, Transaction transaction); /** * Insert the beans with options (ON CONFLICT DO UPDATE | DO NOTHING) and transaction. *

* Currently, this is limited to use with Postgres only, */ void insert(Object bean, InsertOptions insertOptions, Transaction transaction); /** * Insert a collection of beans. If there is no current transaction one is created and used to * insert all the beans in the collection. */ void insertAll(Collection beans); /** * Insert the beans with options - typically ON CONFLICT DO UPDATE | DO NOTHING. *

* Currently, this is limited to use with Postgres only, */ void insertAll(Collection beans, InsertOptions options); /** * Insert a collection of beans with an explicit transaction. */ void insertAll(Collection beans, Transaction transaction); /** * Insert the beans with options (ON CONFLICT DO UPDATE | DO NOTHING) and transaction. *

* Currently, this is limited to use with Postgres only, */ void insertAll(Collection beans, InsertOptions options, Transaction transaction); /** * Execute explicitly passing a transaction. */ int execute(SqlUpdate updSql, Transaction transaction); /** * Execute explicitly passing a transaction. */ int execute(CallableSql callableSql, Transaction transaction); /** * Execute a Runnable in a Transaction with an explicit scope. *

* The scope can control the transaction type, isolation and rollback semantics. * *

{@code
   *  // set specific transactional scope settings
   *  TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
   *
   *  database.execute(scope, new Runnable() {
   *    public void run() {
   *      User u1 = database.find(User.class, 1);
   *      ...
   *    }
   *  });
   *
   * }
*/ void execute(TxScope scope, Runnable runnable); /** * Execute a Runnable in a Transaction with the default scope. *

* The default scope runs with REQUIRED and by default will rollback on any * exception (checked or runtime). * *

{@code
   *  database.execute(() -> {
   *
   *    User u1 = database.find(User.class, 1);
   *    User u2 = database.find(User.class, 2);
   *
   *    u1.setName("u1 mod");
   *    u2.setName("u2 mod");
   *
   *    u1.save();
   *    u2.save();
   *  });
   *
   * }
*/ void execute(Runnable runnable); /** * Execute a TxCallable in a Transaction with an explicit scope. *

* The scope can control the transaction type, isolation and rollback * semantics. * *

{@code
   *   // set specific transactional scope settings
   *   TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
   *
   *   database.executeCall(scope, new Callable() {
   *     public String call() {
   *       User u1 = database.find(User.class, 1);
   *       ...
   *       return u1.getEmail();
   *     }
   *   });
   *
   * }
*/ T executeCall(TxScope scope, Callable callable); /** * Execute a TxCallable in a Transaction with the default scope. *

* The default scope runs with REQUIRED and by default will rollback on any * exception (checked or runtime). * *

{@code
   *   database.executeCall(new Callable() {
   *     public String call() {
   *       User u1 = database.find(User.class, 1);
   *       User u2 = database.find(User.class, 2);
   *
   *       u1.setName("u1 mod");
   *       u2.setName("u2 mod");
   *
   *       database.save(u1);
   *       database.save(u2);
   *
   *       return u1.getEmail();
   *     }
   *   });
   * }
*/ T executeCall(Callable callable); /** * Return the manager of the server cache ("L2" cache). */ ServerCacheManager cacheManager(); /** * Return the BackgroundExecutor service for asynchronous processing of queries. */ BackgroundExecutor backgroundExecutor(); /** * Return the JsonContext for reading/writing JSON. *

* This instance is safe to be used concurrently by multiple threads and this * method is cheap to call. * *

Simple example:

*
{@code
   *   JsonContext json = database.json();
   *   String jsonOutput = json.toJson(list);
   *   System.out.println(jsonOutput);
   * }
* *

*

Using PathProperties:

*
{@code
   *   // specify just the properties we want
   *   PathProperties paths = PathProperties.parse("name, status, anniversary");
   *
   *   List customers =
   *     database.find(Customer.class)
   *       // apply those paths to the query (only fetch what we need)
   *       .apply(paths)
   *       .where().ilike("name", "rob%")
   *       .findList();
   *
   *   // ... get the json
   *   JsonContext jsonContext = database.json();
   *   String json = jsonContext.toJson(customers, paths);
   *
   * }
* * @see FetchPath * @see Query#apply(FetchPath) */ JsonContext json(); /** * Return a ScriptRunner for running SQL or DDL scripts. *

* Intended to use mostly in testing to run seed SQL scripts or truncate table scripts etc. */ ScriptRunner script(); /** * Returns the set of properties/paths that are unknown (do not map to known properties or paths). *

* Validate the query checking the where and orderBy expression paths to confirm if * they represent valid properties/path for the given bean type. */ Set validateQuery(Query query); /** * Load and lock the bean using {@code select for update}. *

* This should be executed inside a transaction and results in the bean being loaded or * refreshed from the database and a database row lock held via {@code select for update}. *

* The bean needs to have an ID property set and can be a reference bean (only has ID) * or partially or fully populated bean. This will load all the properties of the bean * from the database using {@code select for update} obtaining a database row lock (using WAIT). * * @param bean The entity bean that we wish to obtain a database lock on. */ void lock(Object bean); /** * Truncate all the given tables. */ void truncate(String... tables); /** * Truncate the base tables for the given bean types. */ void truncate(Class... beanTypes); }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy