package io.ebean; import io.ebean.cache.ServerCacheManager; import io.ebean.config.ServerConfig; import io.ebean.meta.MetaInfoManager; import io.ebean.plugin.SpiServer; import io.ebean.text.csv.CsvReader; import io.ebean.text.json.JsonContext; import org.jetbrains.annotations.Nullable; import javax.persistence.NonUniqueResultException; import javax.persistence.OptimisticLockException; import javax.persistence.PersistenceException; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.Consumer; import java.util.function.Predicate; /** * Provides the API for fetching and saving beans to a particular DataSource. * <p> * <b>Registration with the Ebean Singleton:</b><br/> * When a EbeanServer is constructed it can be registered with the Ebean * singleton (see {@link ServerConfig#setRegister(boolean)}). The Ebean * singleton is essentially a map of EbeanServer's that have been registered * with it. The EbeanServer can then be retrieved later via * {@link Ebean#getServer(String)}. * </p> * <p> * <b>The 'default' EbeanServer</b><br/> * One EbeanServer can be designated as the 'default' or 'primary' EbeanServer * (see {@link ServerConfig#setDefaultServer(boolean)}. Many methods on Ebean * such as {@link Ebean#find(Class)} etc are actually just a convenient way to * call methods on the 'default/primary' EbeanServer. This is handy for * applications that use a single DataSource. * <p> * There is one EbeanServer per Database (javax.sql.DataSource). One EbeanServer * is referred to as the <em>'default'</em> server and that is the one that * Ebean methods such as {@link Ebean#find(Class)} use. * </p> * <p> * <b>Constructing a EbeanServer</b><br/> * EbeanServer's are constructed by the EbeanServerFactory. They can be created * programmatically via {@link EbeanServerFactory#create(ServerConfig)} or they * can be automatically constructed on demand using configuration information in * the ebean.properties file. * </p> * <p> * Example: Get a EbeanServer * </p> * <p> * <pre>{@code * // Get access to the Human Resources EbeanServer/Database * EbeanServer hrServer = Ebean.getServer("HR"); * * * // fetch contact 3 from the HR database Contact contact = * hrServer.find(Contact.class, new Integer(3)); * * contact.setStatus("INACTIVE"); ... * * // save the contact back to the HR database hrServer.save(contact); * }</pre> * <p> * <p> * <b>EbeanServer has more API than Ebean</b><br/> * EbeanServer provides additional API compared with Ebean. For example it * provides more control over the use of Transactions that is not available in * the Ebean API. * </p> * <p> * <em>External Transactions:</em> If you wanted to use transactions created * externally to eBean then EbeanServer provides additional methods where you * can explicitly pass a transaction (that can be created externally). * </p> * <p> * <em>Bypass ThreadLocal Mechanism:</em> 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. * </p> * * @see Ebean * @see EbeanServerFactory * @see ServerConfig */ public interface EbeanServer { /** * Shutdown the EbeanServer programmatically. * <p> * This method is not normally required. Ebean registers a shutdown hook and shuts down cleanly. * </p> * <p> * If the under underlying DataSource is the Ebean implementation then you * also have the option of shutting down the DataSource and deregistering the * JDBC driver. * </p> * * @param shutdownDataSource if true then shutdown the underlying DataSource if it is the EbeanORM * DataSource implementation. * @param deregisterDriver if true then deregister the JDBC driver if it is the EbeanORM * DataSource implementation. */ void shutdown(boolean shutdownDataSource, boolean deregisterDriver); /** * Return AutoTune which is used to control the AutoTune service at runtime. */ AutoTune getAutoTune(); /** * Return the name. This is used with {@link Ebean#getServer(String)} to get a * EbeanServer that was registered with the Ebean singleton. */ String getName(); /** * Return the ExpressionFactory for this server. */ ExpressionFactory getExpressionFactory(); /** * Return the MetaInfoManager which is used to get meta data from the EbeanServer * such as query execution statistics. */ MetaInfoManager getMetaInfoManager(); /** * Return the extended API intended for use by plugins. */ SpiServer getPluginApi(); /** * Return the BeanState for a given entity bean. * <p> * This will return null if the bean is not an enhanced entity bean. * </p> */ BeanState getBeanState(Object bean); /** * Return the value of the Id property for a given bean. */ Object getBeanId(Object bean); /** * Set the Id value onto the bean converting the type of the id value if necessary. * <p> * 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. * </p> * * @param bean The entity bean to set the id value on. * @param id The id value to set. */ Object setBeanId(Object bean, Object id); /** * Return a map of the differences between two objects of the same type. * <p> * When null is passed in for b, then the 'OldValues' of a is used for the * difference comparison. * </p> */ Map<String, ValuePair> diff(Object newBean, Object oldBean); /** * Create a new instance of T that is an EntityBean. * <p> * Useful if you use BeanPostConstructListeners or @PostConstruct Annotations. * In this case you should not use "new Bean...()". Making all bean construtors protected * could be a good idea here. * </p> */ <T> T createEntityBean(Class<T> type); /** * Create a CsvReader for a given beanType. */ <T> CsvReader<T> createCsvReader(Class<T> beanType); /** * Create an Update query to perform a bulk update. * <p> * <pre>{@code * * int rows = ebeanServer * .update(Customer.class) * .set("status", Customer.Status.ACTIVE) * .set("updtime", new Timestamp(System.currentTimeMillis())) * .where() * .gt("id", 1000) * .update(); * * }</pre> * * @param beanType The type of entity bean to update * @param <T> The type of entity bean * @return The update query to use */ <T> UpdateQuery<T> update(Class<T> beanType); /** * Create a named query. * <p> * For RawSql the named query is expected to be in ebean.xml. * </p> * * @param beanType The type of entity bean * @param namedQuery The name of the query * @param <T> The type of entity bean * @return The query */ <T> Query<T> createNamedQuery(Class<T> beanType, String namedQuery); /** * Create a query for an entity bean and synonym for {@link #find(Class)}. * * @see #find(Class) */ <T> Query<T> createQuery(Class<T> beanType); /** * Parse the Ebean query language statement returning the query which can then * be modified (add expressions, change order by clause, change maxRows, change * fetch and select paths etc). * <p> * <h3>Example</h3> * <pre>{@code * * // Find order additionally fetching the customer, details and details.product name. * * String ormQuery = "fetch customer fetch details fetch details.product (name) where id = :orderId "; * * Query<Order> query = Ebean.createQuery(Order.class, ormQuery); * query.setParameter("orderId", 2); * * Order order = query.findUnique(); * * // This is the same as: * * Order order = Ebean.find(Order.class) * .fetch("customer") * .fetch("details") * .fetch("detail.product", "name") * .setId(2) * .findUnique(); * * }</pre> * * @param beanType The type of bean to fetch * @param ormQuery The Ebean ORM query * @param <T> The type of the entity bean * @return The query with expressions defined as per the parsed query statement */ <T> Query<T> createQuery(Class<T> beanType, String ormQuery); /** * Create a query for a type of entity bean. * <p> * You can use the methods on the Query object to specify fetch paths, * predicates, order by, limits etc. * </p> * <p> * You then use findList(), findSet(), findMap() and findUnique() to execute * the query and return the collection or bean. * </p> * <p> * Note that a query executed by {@link Query#findList()} * {@link Query#findSet()} etc will execute against the same EbeanServer from * which is was created. * </p> * <p> * <pre>{@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 = ebeanServer.find(Order.class) * .fetch("customer") * .fetch("details") * .fetch("detail.product", "name") * .setId(2) * .findUnique(); * * // find some new orders ... with firstRow/maxRows * List<Order> orders = * ebeanServer.find(Order.class) * .where().eq("status", Order.Status.NEW) * .setFirstRow(20) * .setMaxRows(10) * .findList(); * * }</pre> */ <T> Query<T> find(Class<T> beanType); /** * Create a query using native SQL. * <p> * The native SQL can contain named parameters or positioned parameters. * </p> * <pre>{@code * * String sql = "select c.id, c.name from customer c where c.name like ? order by c.name"; * * Query<Customer> query = ebeanServer.findNative(Customer.class, sql); * query.setParameter(1, "Rob%"); * * List<Customer> customers = query.findList(); * * }</pre> * * @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 */ <T> Query<T> findNative(Class<T> beanType, String nativeSql); /** * Return the next unique identity value for a given bean type. * <p> * This will only work when a IdGenerator is on the bean such as for beans * that use a DB sequence or UUID. * </p> * <p> * 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. * </p> */ Object nextId(Class<?> beanType); /** * Create a filter for sorting and filtering lists of entities locally without * going back to the database. * <p> * This produces and returns a new list with the sort and filters applied. * </p> * <p> * Refer to {@link Filter} for an example of its use. * </p> */ <T> Filter<T> filter(Class<T> 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. * <ul> * <li>asc - ascending order (which is the default)</li> * <li>desc - Descending order</li> * <li>nullsHigh - Treat null values as high/large values (which is the * default)</li> * <li>nullsLow- Treat null values as low/very small values</li> * </ul> * <p> * If you leave off any keywords the defaults are ascending order and treating * nulls as high values. * </p> * <p> * Note that the sorting uses a Comparator and Collections.sort(); and does * not invoke a DB query. * </p> * <p> * <pre>{@code * * // find orders and their customers * List<Order> list = ebeanServer.find(Order.class) * .fetch("customer") * .orderBy("id") * .findList(); * * // sort by customer name ascending, then by order shipDate * // ... then by the order status descending * ebeanServer.sort(list, "customer.name, shipDate, status desc"); * * // sort by customer name descending (with nulls low) * // ... then by the order id * ebeanServer.sort(list, "customer.name desc nullsLow, id"); * * }</pre> * * @param list the list of entity beans * @param sortByClause the properties to sort the list by */ <T> void sort(List<T> list, String sortByClause); /** * Create a 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). * <p> * 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. * </p> * <p> * An example: * </p> * <p> * <pre>{@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<Topic> update = ebeanServer.createUpdate(Topic.class, updStatement); * * update.set("pc", 9); * update.set("id", 3); * * int rows = update.execute(); * System.out.println("rows updated:" + rows); * * }</pre> */ <T> Update<T> createUpdate(Class<T> beanType, String ormUpdate); /** * Create a SqlQuery for executing native sql * query statements. * <p> * Note that you can use raw SQL with entity beans, refer to the SqlSelect * annotation for examples. * </p> */ SqlQuery createSqlQuery(String sql); /** * Create a sql update for executing native dml statements. * <p> * 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. * </p> * <p> * See {@link SqlUpdate} for example usage. * </p> */ SqlUpdate createSqlUpdate(String sql); /** * Create a CallableSql to execute a given stored procedure. */ CallableSql createCallableSql(String callableSql); /** * Register a TransactionCallback on the currently active transaction. * <p/> * 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. * <p> * You will want to do this if you want multiple Transactions in a single * thread or generally use transactions outside of the TransactionThreadLocal * management. * </p> */ Transaction createTransaction(); /** * Create a new transaction additionally specifying the isolation level. * <p> * Note that this transaction is NOT stored in a thread local. * </p> */ Transaction createTransaction(TxIsolation isolation); /** * Start a transaction with 'REQUIRED' semantics. * <p> * With REQUIRED semantics if an active transaction already exists that transaction will be used. * </p> * <p> * The transaction is stored in a ThreadLocal variable and typically you only * need to use the returned Transaction <em>IF</em> you wish to do things like * use batch mode, change the transaction isolation level, use savepoints or * log comments to the transaction log. * </p> * <p> * Example of using a transaction to span multiple calls to find(), save() * etc. * </p> * <p> * <pre>{@code * * // start a transaction (stored in a ThreadLocal) * ebeanServer.beginTransaction(); * try { * Order order = ebeanServer.find(Order.class,10); * * ebeanServer.save(order); * * ebeanServer.commitTransaction(); * * } finally { * // rollback if we didn't commit * // i.e. an exception occurred before commitTransaction(). * ebeanServer.endTransaction(); * } * * }</pre> * <p> * <h3>Transaction options:</h3> * <pre>{@code * * Transaction txn = ebeanServer.beginTransaction(); * try { * // 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.flushBatch(); * * ... * * txn.commit(); * * } finally { * // rollback if necessary * txn.end(); * } * * }</pre> * <p> * <p> * If you want to externalise the transaction management then you use * createTransaction() and pass the transaction around to the various methods on * EbeanServer yourself. * </p> */ Transaction beginTransaction(); /** * Start a transaction additionally specifying the isolation level. */ Transaction beginTransaction(TxIsolation isolation); /** * Start a transaction typically specifying REQUIRES_NEW or REQUIRED semantics. * <p> * <p> * Note that this provides an try finally alternative to using {@link #execute(TxScope, TxCallable)} or * {@link #execute(TxScope, TxRunnable)}. * </p> * <p> * <h3>REQUIRES_NEW example:</h3> * <pre>{@code * // Start a new transaction. If there is a current transaction * // suspend it until this transaction ends * Transaction txn = server.beginTransaction(TxScope.requiresNew()); * try { * * ... * * // commit the transaction * txn.commit(); * * } finally { * // end this transaction which: * // A) will rollback transaction if it has not been committed already * // B) will restore a previously suspended transaction * txn.end(); * } * * }</pre> * <p> * <h3>REQUIRED example:</h3> * <pre>{@code * * // start a new transaction if there is not a current transaction * Transaction txn = server.beginTransaction(TxScope.required()); * try { * * ... * * // commit the transaction if it was created or * // do nothing if there was already a current transaction * txn.commit(); * * } finally { * // end this transaction which will rollback the transaction * // if it was created for this try finally scope and has not * // already been committed * txn.end(); * } * * }</pre> */ 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. * <p> * 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. * </p> * <p> * This is the same as <code>currentTransaction().flush()</code>. * </p> */ void flush(); /** * Commit the current transaction. */ void commitTransaction(); /** * Rollback the current transaction. */ void rollbackTransaction(); /** * If the current transaction has already been committed do nothing otherwise * rollback the transaction. * <p> * Useful to put in a finally block to ensure the transaction is ended, rather * than a rollbackTransaction() in each catch block. * </p> * <p> * Code example: * <p> * <pre>{@code * * ebeanServer.beginTransaction(); * try { * // do some fetching and or persisting ... * * // commit at the end * ebeanServer.commitTransaction(); * * } finally { * // if commit didn't occur then rollback the transaction * ebeanServer.endTransaction(); * } * * }</pre> * <p> * </p> */ void endTransaction(); /** * Refresh the values of a bean. * <p> * Note that this resets OneToMany and ManyToMany properties so that if they * are accessed a lazy load will refresh the many property. * </p> */ 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. * <p> * <pre>{@code * // Fetch order 1 * Order order = ebeanServer.find(Order.class, 1); * }</pre> * <p> * <p> * If you want more control over the query then you can use createQuery() and * Query.findUnique(); * </p> * <p> * <pre>{@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<Order> query = ebeanServer.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.findUnique(); * * // traverse the object graph... * * Customer customer = order.getCustomer(); * Address shippingAddress = customer.getShippingAddress(); * List<OrderDetail> details = order.getDetails(); * OrderDetail detail0 = details.get(0); * Product product = detail0.getProduct(); * String productName = product.getName(); * * }</pre> * * @param beanType the type of entity bean to fetch * @param id the id value */ <T> T find(Class<T> beanType, Object id); /** * Get a reference object. * <p> * This will not perform a query against the database unless some property other * that the id property is accessed. * </p> * <p> * It is most commonly used to set a 'foreign key' on another bean like: * </p> * <pre>{@code * * Product product = ebeanServer.getReference(Product.class, 1); * * OrderDetail orderDetail = new OrderDetail(); * // set the product 'foreign key' * orderDetail.setProduct(product); * orderDetail.setQuantity(42); * ... * * ebeanServer.save(orderDetail); * * * }</pre> * <p> * <h3>Lazy loading characteristics</h3> * <pre>{@code * * Product product = ebeanServer.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(); * * }</pre> * * @param beanType the type of entity bean * @param id the id value */ <T> T getReference(Class<T> beanType, Object id); /** * Return the number of 'top level' or 'root' entities this query should return. * * @see Query#findCount() * @see Query#findFutureCount() */ <T> int findCount(Query<T> query, Transaction transaction); /** * Return the Id values of the query as a List. * * @see Query#findIds() */ <A, T> List<A> findIds(Query<T> query, Transaction transaction); /** * Return a QueryIterator for the query. * <p> * Generally using {@link #findEach(Query, Consumer, Transaction)} or * {@link #findEachWhile(Query, Predicate, Transaction)} is preferred * to findIterate(). The reason is that those methods automatically take care of * closing the queryIterator (and the underlying jdbc statement and resultSet). * </p> * <p> * This is similar to findEach in that not all the result beans need to be held * in memory at the same time and as such is good for processing large queries. * </p> * * @see Query#findIterate() * @see Query#findEach(Consumer) * @see Query#findEachWhile(Predicate) */ <T> QueryIterator<T> findIterate(Query<T> query, Transaction transaction); /** * Execute the query visiting the each bean one at a time. * <p> * Unlike findList() this is suitable for processing a query that will return * a very large resultSet. The reason is that not all the result beans need to be * held in memory at the same time and instead processed one at a time. * </p> * <p> * Internally this query using a PersistenceContext scoped to each bean (and the * beans associated object graph). * </p> * <p> * <pre>{@code * * ebeanServer.find(Order.class) * .where().eq("status", Order.Status.NEW) * .order().asc("id") * .findEach((Order order) -> { * * // do something with the order bean * System.out.println(" -- processing order ... " + order); * }); * * }</pre> * * @see Query#findEach(Consumer) * @see Query#findEachWhile(Predicate) */ <T> void findEach(Query<T> query, Consumer<T> consumer, Transaction transaction); /** * Execute the query visiting the each bean one at a time. * <p> * Compared to findEach() this provides the ability to stop processing the query * results early by returning false for the QueryEachWhileConsumer. * </p> * <p> * Unlike findList() this is suitable for processing a query that will return * a very large resultSet. The reason is that not all the result beans need to be * held in memory at the same time and instead processed one at a time. * </p> * <p> * Internally this query using a PersistenceContext scoped to each bean (and the * beans associated object graph). * </p> * <p> * <pre>{@code * * ebeanServer.find(Order.class) * .where().eq("status", Order.Status.NEW) * .order().asc("id") * .findEachWhile((Order order) -> { * * // do something with the order bean * System.out.println(" -- processing order ... " + order); * * boolean carryOnProcessing = ... * return carryOnProcessing; * }); * * }</pre> * * @see Query#findEach(Consumer) * @see Query#findEachWhile(Predicate) */ <T> void findEachWhile(Query<T> query, Predicate<T> consumer, Transaction transaction); /** * Return versions of a @History entity bean. * <p> * Generally this query is expected to be a find by id or unique predicates query. * It will execute the query against the history returning the versions of the bean. * </p> */ <T> List<Version<T>> findVersions(Query<T> query, Transaction transaction); /** * Execute a query returning a list of beans. * <p> * Generally you are able to use {@link Query#findList()} rather than * explicitly calling this method. You could use this method if you wish to * explicitly control the transaction used for the query. * </p> * <p> * <pre>{@code * * List<Customer> customers = * ebeanServer.find(Customer.class) * .where().ilike("name", "rob%") * .findList(); * * }</pre> * * @param <T> the type of entity bean to fetch. * @param query the query to execute. * @param transaction the transaction to use (can be null). * @return the list of fetched beans. * @see Query#findList() */ <T> List<T> findList(Query<T> query, Transaction transaction); /** * Execute find row count query in a background thread. * <p> * This returns a Future object which can be used to cancel, check the * execution status (isDone etc) and get the value (with or without a * timeout). * </p> * * @param query the query to execute the row count on * @param transaction the transaction (can be null). * @return a Future object for the row count query * @see Query#findFutureCount() */ <T> FutureRowCount<T> findFutureCount(Query<T> query, Transaction transaction); /** * Execute find Id's query in a background thread. * <p> * This returns a Future object which can be used to cancel, check the * execution status (isDone etc) and get the value (with or without a * timeout). * </p> * * @param query the query to execute the fetch Id's on * @param transaction the transaction (can be null). * @return a Future object for the list of Id's * @see Query#findFutureIds() */ <T> FutureIds<T> findFutureIds(Query<T> query, Transaction transaction); /** * Execute find list query in a background thread returning a FutureList object. * <p> * This returns a Future object which can be used to cancel, check the * execution status (isDone etc) and get the value (with or without a timeout). * <p> * This query will execute in it's own PersistenceContext and using its own transaction. * What that means is that it will not share any bean instances with other queries. * * @param query the query to execute in the background * @param transaction the transaction (can be null). * @return a Future object for the list result of the query * @see Query#findFutureList() */ <T> FutureList<T> findFutureList(Query<T> query, Transaction transaction); /** * Return a PagedList for this query using firstRow and maxRows. * <p> * The benefit of using this over findList() is that it provides functionality to get the * total row count etc. * </p> * <p> * If maxRows is not set on the query prior to calling findPagedList() then a * PersistenceException is thrown. * </p> * <p> * <pre>{@code * * PagedList<Order> pagedList = Ebean.find(Order.class) * .setFirstRow(50) * .setMaxRows(20) * .findPagedList(); * * // fetch the total row count in the background * pagedList.loadRowCount(); * * List<Order> orders = pagedList.getList(); * int totalRowCount = pagedList.getTotalRowCount(); * * }</pre> * * @return The PagedList * @see Query#findPagedList() */ <T> PagedList<T> findPagedList(Query<T> query, Transaction transaction); /** * Execute the query returning a set of entity beans. * <p> * Generally you are able to use {@link Query#findSet()} rather than * explicitly calling this method. You could use this method if you wish to * explicitly control the transaction used for the query. * </p> * <p> * <pre>{@code * * Set<Customer> customers = * ebeanServer.find(Customer.class) * .where().ilike("name", "rob%") * .findSet(); * * }</pre> * * @param <T> the type of entity bean to fetch. * @param query the query to execute * @param transaction the transaction to use (can be null). * @return the set of fetched beans. * @see Query#findSet() */ <T> Set<T> findSet(Query<T> query, Transaction transaction); /** * Execute the query returning the entity beans in a Map. * <p> * Generally you are able to use {@link Query#findMap()} rather than * explicitly calling this method. You could use this method if you wish to * explicitly control the transaction used for the query. * </p> * * @param <T> the type of entity bean to fetch. * @param query the query to execute. * @param transaction the transaction to use (can be null). * @return the map of fetched beans. * @see Query#findMap() */ <K, T> Map<K, T> findMap(Query<T> query, Transaction transaction); /** * Execute the query returning a list of values for a single property. * <p> * <h3>Example 1:</h3> * <pre>{@code * * List<String> names = * Ebean.find(Customer.class) * .select("name") * .orderBy().asc("name") * .findSingleAttributeList(); * * }</pre> * <h3>Example 2:</h3> * <pre>{@code * * List<String> names = * Ebean.find(Customer.class) * .setDistinct(true) * .select("name") * .where().eq("status", Customer.Status.NEW) * .orderBy().asc("name") * .setMaxRows(100) * .findSingleAttributeList(); * * }</pre> * * @return the list of values for the selected property * @see Query#findSingleAttributeList() */ <A, T> List<A> findSingleAttributeList(Query<T> query, Transaction transaction); /** * Execute the query returning at most one entity bean or null (if no matching * bean is found). * <p> * This will throw a NonUniqueResultException if the query finds more than one result. * </p> * <p> * Generally you are able to use {@link Query#findOne()} rather than * explicitly calling this method. You could use this method if you wish to * explicitly control the transaction used for the query. * </p> * * @param <T> the type of entity bean to fetch. * @param query the query to execute. * @param transaction the transaction to use (can be null). * @return the list of fetched beans. * @throws NonUniqueResultException if more than one result was found * @see Query#findOne() */ @Nullable <T> T findOne(Query<T> query, Transaction transaction); /** * Similar to findOne() but returns an Optional (rather than nullable). */ <T> Optional<T> findOneOrEmpty(Query<T> query, Transaction transaction); /** * Synonym for findOne(). * <p> * This proceeded findOne which was introduced to better match spring data. * This will be deprecated at some future point. * </p> */ @Nullable <T> T findUnique(Query<T> query, Transaction transaction); /** * Execute as a delete query deleting the 'root level' beans that match the predicates * in the query. * <p> * Note that if the query includes joins then the generated delete statement may not be * optimal depending on the database platform. * </p> * * @param query the query used for the delete * @param transaction the transaction to use (can be null) * @param <T> the type of entity bean to fetch. * @return the number of beans/rows that were deleted */ <T> int delete(Query<T> query, Transaction transaction); /** * Execute the update query returning the number of rows updated. * <p> * The update query must be created using {@link #update(Class)}. * </p> * * @param query the update query to execute * @param transaction the optional transaction to use for the update (can be null) * @param <T> the type of entity bean * @return The number of rows updated */ <T> int update(Query<T> query, Transaction transaction); /** * Execute the sql query returning a list of MapBean. * <p> * Generally you are able to use {@link SqlQuery#findList()} rather than * explicitly calling this method. You could use this method if you wish to * explicitly control the transaction used for the query. * </p> * * @param query the query to execute. * @param transaction the transaction to use (can be null). * @return the list of fetched MapBean. * @see SqlQuery#findList() */ List<SqlRow> findList(SqlQuery query, Transaction transaction); /** * Execute the SqlQuery iterating a row at a time. * <p> * This streaming type query is useful for large query execution as only 1 row needs to be held in memory. * </p> */ void findEach(SqlQuery query, Consumer<SqlRow> consumer, Transaction transaction); /** * Execute the SqlQuery iterating a row at a time with the ability to stop consuming part way through. * <p> * Returning false after processing a row stops the iteration through the query results. * </p> * <p> * This streaming type query is useful for large query execution as only 1 row needs to be held in memory. * </p> */ void findEachWhile(SqlQuery query, Predicate<SqlRow> consumer, Transaction transaction); /** * Execute the sql query returning a single MapBean or null. * <p> * This will throw a PersistenceException if the query found more than one * result. * </p> * <p> * Generally you are able to use {@link SqlQuery#findUnique()} rather than * explicitly calling this method. You could use this method if you wish to * explicitly control the transaction used for the query. * </p> * * @param query the query to execute. * @param transaction the transaction to use (can be null). * @return the fetched MapBean or null if none was found. * @see SqlQuery#findUnique() */ @Nullable SqlRow findOne(SqlQuery query, Transaction transaction); /** * Synonym for findOne(). * <p> * This proceeded findOne which was introduced to better match spring data. * This will be deprecated at some future point. * </p> */ @Nullable SqlRow findUnique(SqlQuery query, Transaction transaction); /** * Either Insert or Update the bean depending on its state. * <p> * If there is no current transaction one will be created and committed for * you automatically. * </p> * <p> * 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. * </p> * <p> * In this example below the details property has a CascadeType.ALL set so * saving an order will also save all its details. * </p> * <p> * <pre>{@code * public class Order { ... * * @OneToMany(cascade=CascadeType.ALL, mappedBy="order") * List<OrderDetail> details; * ... * } * }</pre> * <p> * <p> * 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. * </p> */ void save(Object bean) throws OptimisticLockException; /** * Save all the beans in the collection. */ int saveAll(Collection<?> beans) throws OptimisticLockException; /** * Delete the bean. * <p> * This will return true if the bean was deleted successfully or JDBC batch is being used. * </p> * <p> * If there is no current transaction one will be created and committed for * you automatically. * </p> * <p> * 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. * </p> */ boolean delete(Object bean) throws OptimisticLockException; /** * Delete the bean with an explicit transaction. * <p> * This will return true if the bean was deleted successfully or JDBC batch is being used. * </p> * <p> * 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. * </p> */ 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(). * <p> * If you wish to execute a Sql Select natively then you should use the * FindByNativeSql object. * </p> * <p> * Note that the table modification information is automatically deduced and * you do not need to call the Ebean.externalModification() method when you * use this method. * </p> * <p> * Example: * </p> * <p> * <pre>{@code * * // example that uses 'named' parameters * String s = "UPDATE f_topic set post_count = :count where id = :id" * * SqlUpdate update = ebeanServer.createSqlUpdate(s); * * update.setParameter("id", 1); * update.setParameter("count", 50); * * int modifiedCount = ebeanServer.execute(update); * * String msg = "There where " + modifiedCount + "rows updated"; * * }</pre> * * @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. * <p> * This returns the number of rows that where inserted, updated or deleted. * </p> */ 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. * <p> * Example: * </p> * <p> * <pre>{@code * * String sql = "{call sp_order_modify(?,?,?)}"; * * CallableSql cs = ebeanServer.createCallableSql(sql); * cs.setParameter(1, 27); * cs.setParameter(2, "SHIPPED"); * cs.registerOut(3, Types.INTEGER); * * ebeanServer.execute(cs); * * // read the out parameter * Integer returnValue = (Integer) cs.getObject(3); * * }</pre> * * @see CallableSql * @see Ebean#execute(SqlUpdate) */ 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. * <p> * If you use ebeanServer.execute(UpdateSql) then the table modification information * is automatically deduced and you do not need to call this method yourself. * </p> * <p> * This information is used to invalidate objects out of the cache and * potentially text indexes. This information is also automatically broadcast * across the cluster. * </p> * <p> * 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. * </p> * <p> * If there is NO current transaction when you call this method then this * information is registered immediately (with the transaction manager). * </p> * * @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 <T> 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) */ <T> T find(Class<T> 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; /** * Marks the entity bean as dirty. * <p> * This is used so that when a bean that is otherwise unmodified is updated the version * property is updated. * <p> * An unmodified bean that is saved or updated is normally skipped and this marks the bean as * dirty so that it is not skipped. * <p> * <pre>{@code * * Customer customer = ebeanServer.find(Customer, id); * * // mark the bean as dirty so that a save() or update() will * // increment the version property * ebeanServer.markAsDirty(customer); * ebeanServer.save(customer); * * }</pre> */ 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(). * <p> * <b>Stateless updates:</b> 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'. * </p> * <p> * <b>Optimistic Locking: </b> Note that if the version property is not set when update() is * called then no optimistic locking is performed (internally ConcurrencyMode.NONE is used). * </p> * <p> * <b>{@link ServerConfig#setUpdatesDeleteMissingChildren(boolean)}: </b> When cascade saving to a * OneToMany or ManyToMany the updatesDeleteMissingChildren setting controls if any other children * that are in the database but are not in the collection are deleted. * </p> * <p> * <b>{@link ServerConfig#setUpdateChangesOnly(boolean)}: </b> The updateChangesOnly setting * controls if only the changed properties are included in the update or if all the loaded * properties are included instead. * </p> * <p> * <pre>{@code * * // A 'stateless update' example * Customer customer = new Customer(); * customer.setId(7); * customer.setName("ModifiedNameNoOCC"); * ebeanServer.update(customer); * * }</pre> * * @see ServerConfig#setUpdatesDeleteMissingChildren(boolean) * @see ServerConfig#setUpdateChangesOnly(boolean) */ void update(Object bean) throws OptimisticLockException; /** * Update a bean additionally specifying a transaction. */ void update(Object bean, Transaction transaction) throws OptimisticLockException; /** * Update a bean additionally specifying a transaction and the deleteMissingChildren setting. * * @param bean the bean to update * @param transaction the transaction to use (can be null). * @param deleteMissingChildren specify false if you do not want 'missing children' of a OneToMany * or ManyToMany to be automatically deleted. */ void update(Object bean, Transaction transaction, boolean deleteMissingChildren) 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; /** * Insert the bean. * <p> * 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). * </p> */ void insert(Object bean); /** * Insert the bean with a transaction. */ void insert(Object bean, 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 a collection of beans with an explicit transaction. */ void insertAll(Collection<?> beans, 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 TxRunnable in a Transaction with an explicit scope. * <p> * The scope can control the transaction type, isolation and rollback * semantics. * </p> * <p> * <pre>{@code * * // set specific transactional scope settings * TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE); * * ebeanServer.execute(scope, new TxRunnable() { * public void run() { * User u1 = Ebean.find(User.class, 1); * ... * } * }); * * }</pre> */ void execute(TxScope scope, TxRunnable runnable); /** * Execute a TxRunnable in a Transaction with the default scope. * <p> * The default scope runs with REQUIRED and by default will rollback on any * exception (checked or runtime). * </p> * <p> * <pre>{@code * * ebeanServer.execute(new TxRunnable() { * public void run() { * User u1 = ebeanServer.find(User.class, 1); * User u2 = ebeanServer.find(User.class, 2); * * u1.setName("u1 mod"); * u2.setName("u2 mod"); * * ebeanServer.save(u1); * ebeanServer.save(u2); * } * }); * * }</pre> */ void execute(TxRunnable runnable); /** * Execute a TxCallable in a Transaction with an explicit scope. * <p> * The scope can control the transaction type, isolation and rollback * semantics. * </p> * <p> * <pre>{@code * * // set specific transactional scope settings * TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE); * * ebeanServer.execute(scope, new TxCallable<String>() { * public String call() { * User u1 = ebeanServer.find(User.class, 1); * ... * return u1.getEmail(); * } * }); * * }</pre> */ <T> T execute(TxScope scope, TxCallable<T> callable); /** * Execute a TxCallable in a Transaction with the default scope. * <p> * The default scope runs with REQUIRED and by default will rollback on any * exception (checked or runtime). * </p> * <p> * This is basically the same as TxRunnable except that it returns an Object * (and you specify the return type via generics). * </p> * <p> * <pre>{@code * * ebeanServer.execute(new TxCallable<String>() { * public String call() { * User u1 = ebeanServer.find(User.class, 1); * User u2 = ebeanServer.find(User.class, 2); * * u1.setName("u1 mod"); * u2.setName("u2 mod"); * * ebeanServer.save(u1); * ebeanServer.save(u2); * * return u1.getEmail(); * } * }); * * }</pre> */ <T> T execute(TxCallable<T> callable); /** * Return the manager of the server cache ("L2" cache). */ ServerCacheManager getServerCacheManager(); /** * Return the BackgroundExecutor service for asynchronous processing of * queries. */ BackgroundExecutor getBackgroundExecutor(); /** * Return the JsonContext for reading/writing JSON. * <p> * This instance is safe to be used concurrently by multiple threads and this * method is cheap to call. * </p> * <p> * <h3>Simple example:</h3> * <pre>{@code * * JsonContext json = ebeanServer.json(); * String jsonOutput = json.toJson(list); * System.out.println(jsonOutput); * * }</pre> * <p> * <h3>Using PathProperties:</h3> * <pre>{@code * * // specify just the properties we want * PathProperties paths = PathProperties.parse("name, status, anniversary"); * * List<Customer> customers = * ebeanServer.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 = ebeanServer.json(); * String json = jsonContext.toJson(customers, paths); * * }</pre> * * @see FetchPath * @see Query#apply(FetchPath) */ JsonContext json(); /** * Return the Document store. */ DocumentStore docStore(); /** * Publish a single bean given its type and id returning the resulting live bean. * <p> * The values are published from the draft to the live bean. * </p> * * @param <T> the type of the entity bean * @param beanType the type of the entity bean * @param id the id of the entity bean * @param transaction the transaction the publish process should use (can be null) */ <T> T publish(Class<T> beanType, Object id, Transaction transaction); /** * Publish a single bean given its type and id returning the resulting live bean. * This will use the current transaction or create one if required. * <p> * The values are published from the draft to the live bean. * </p> * * @param <T> the type of the entity bean * @param beanType the type of the entity bean * @param id the id of the entity bean */ <T> T publish(Class<T> beanType, Object id); /** * Publish the beans that match the query returning the resulting published beans. * <p> * The values are published from the draft beans to the live beans. * </p> * * @param <T> the type of the entity bean * @param query the query used to select the draft beans to publish * @param transaction the transaction the publish process should use (can be null) */ <T> List<T> publish(Query<T> query, Transaction transaction); /** * Publish the beans that match the query returning the resulting published beans. * This will use the current transaction or create one if required. * <p> * The values are published from the draft beans to the live beans. * </p> * * @param <T> the type of the entity bean * @param query the query used to select the draft beans to publish */ <T> List<T> publish(Query<T> query); /** * Restore the draft bean back to the live state. * <p> * The values from the live beans are set back to the draft bean and the * <code>@DraftDirty</code> and <code>@DraftReset</code> properties are reset. * </p> * * @param <T> the type of the entity bean * @param beanType the type of the entity bean * @param id the id of the entity bean to restore * @param transaction the transaction the restore process should use (can be null) */ <T> T draftRestore(Class<T> beanType, Object id, Transaction transaction); /** * Restore the draft bean back to the live state. * <p> * The values from the live beans are set back to the draft bean and the * <code>@DraftDirty</code> and <code>@DraftReset</code> properties are reset. * </p> * * @param <T> the type of the entity bean * @param beanType the type of the entity bean * @param id the id of the entity bean to restore */ <T> T draftRestore(Class<T> beanType, Object id); /** * Restore the draft beans matching the query back to the live state. * <p> * The values from the live beans are set back to the draft bean and the * <code>@DraftDirty</code> and <code>@DraftReset</code> properties are reset. * </p> * * @param <T> the type of the entity bean * @param query the query used to select the draft beans to restore * @param transaction the transaction the restore process should use (can be null) */ <T> List<T> draftRestore(Query<T> query, Transaction transaction); /** * Restore the draft beans matching the query back to the live state. * <p> * The values from the live beans are set back to the draft bean and the * <code>@DraftDirty</code> and <code>@DraftReset</code> properties are reset. * </p> * * @param <T> the type of the entity bean * @param query the query used to select the draft beans to restore */ <T> List<T> draftRestore(Query<T> query); /** * Returns the set of properties/paths that are unknown (do not map to known properties or paths). * <p> * Validate the query checking the where and orderBy expression paths to confirm if * they represent valid properties/path for the given bean type. * </p> */ <T> Set<String> validateQuery(Query<T> query); }