diff --git a/.editorconfig b/.editorconfig
index 837d975fa..18b710430 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -10,3 +10,4 @@ indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
spaces_around_operators = true
+max_line_length = 130
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 000000000..2e27fa4e0
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,3 @@
+# These are supported funding model platforms
+
+custom: https://ebean.io/sponsors
diff --git a/.gitignore b/.gitignore
index 0d96b2f95..1b88dd830 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,3 +20,4 @@ profiling/
*.ipr
*.iws
.idea/
+*uuid.state
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index 372ace1ff..5fcaa8a7e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,22 +3,34 @@ sudo: required
language: java
jdk:
- oraclejdk8
+ - openjdk11
git:
depth: 3
addons:
postgresql: "9.6"
+# apt:
+# packages:
+# - mysql-server-5.7
+# - mysql-client-core-5.7
+# - mysql-client-5.7
services:
+ - docker
- postgresql
+ - mysql
before_script:
- ./.travis/setup_database
+ - mysql -u root -e 'CREATE DATABASE test_ebean;'
+ - mysql -u root -e "CREATE USER 'test_ebean'@'localhost' IDENTIFIED BY 'test';"
+ - mysql -u root -e "GRANT ALL ON test_ebean.* TO 'test_ebean'@'localhost';"
env:
- EBEAN_DB=h2
- EBEAN_DB=pg
+# - EBEAN_DB=mysql
install: true
diff --git a/CONFIGURATION.md b/CONFIGURATION.md
new file mode 100644
index 000000000..16fa6d698
--- /dev/null
+++ b/CONFIGURATION.md
@@ -0,0 +1,298 @@
+Overview of ebean.properties file
+=================================
+
+
+### DbMigration options
+
+You can set individual values for different platforms when generating migrations
+
+`dbmigration.platform.
+
+
+
# Need help?
Post questions or issues to the Ebean google group - https://groups.google.com/forum/#!forum/ebean
# Documentation
-Goto [https://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Website")
+Goto [https://ebean.io/docs/](https://ebean.io/docs/)
## Maven cental links:
@@ -10,8 +41,7 @@ Goto [https://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Web
[Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cebean "maven central all related projects")
-## Current versions
-* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean) - ebean
-* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-agent) - ebean-agent
-* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-maven-plugin) - ebean-maven-plugin
+## Other versions
+* [](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-agent) - ebean-agent
+* [](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-maven-plugin) - ebean-maven-plugin
diff --git a/howto-test.md b/howto-test.md
index 243ed5200..ed159cac2 100644
--- a/howto-test.md
+++ b/howto-test.md
@@ -48,7 +48,8 @@ Reqirements
run: `mvn clean test -Ddatasource.default=pg`
Current status: PASS
-Tests run: 1986, Failures: 0, Errors: 0, Skipped: 16
+Tests run: 2166, Failures: 0, Errors: 0, Skipped: 25
+
'mysql' platform
@@ -61,8 +62,8 @@ Reqirements
run: `mvn clean test -Ddatasource.default=mysql`
-Current status: FAIL
-Tests run: 1986, Failures: 2, Errors: 4, Skipped: 16
+Current status: PASS
+Tests run: 2166, Failures: 0, Errors: 0, Skipped: 33
@@ -76,8 +77,8 @@ Reqires an installed sqlserver - e.g. https://hub.docker.com/r/microsoft/mssql-s
run: `mvn clean test -Ddatasource.default=mssql`
-Current status: FAIL
-Tests run: 1986, Failures: 19, Errors: 43, Skipped: 16
+Current status: PASS
+Tests run: 2166, Failures: 0, Errors: 0, Skipped: 39
@@ -107,7 +108,7 @@ Reqires a locally installed DB2 Express-C server.
run: `mvn clean test -Ddatasource.default=db2 -Pdb2`
Current status: FAIL
-Tests run: 1986, Failures: 33, Errors: 26, Skipped: 16
+Tests run: 2166, Failures: 29, Errors: 58, Skipped: 30
'sqlite' platform
@@ -150,3 +151,18 @@ In `InsertHandler.getPstmt` the `meta.getIdentityDbColumns()` contains
TODO: not yet tested
+
+'hana' platform
+--------------------
+
+Requires an installed SAP HANA server - e.g. https://store.docker.com/images/sap-hana-express-edition
+
+- Create a user `EBEAN_TEST` with password `Eb3an_test` in the tenant database `HXE`
+- Adjust the connection string and/or username in `ebean.properties`
+
+run: `mvn clean test -Ddatasource.default=hana`
+
+Current status: PASS
+Tests run: 2486, Failures: 0, Errors: 0, Skipped: 84
+
+
diff --git a/pom.xml b/pom.xml
index f3e7f3cb5..2b1fc0bc7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -9,12 +9,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ * Note that typically users would extend BeanRepository rather than BeanFinder. + *
+ *{@code
+ *
+ * public class CustomerFinder extends BeanFinder {
+ *
+ * @Inject
+ * public CustomerFinder(Database database) {
+ * super(Customer.class, database);
+ * }
+ *
+ * // ... add customer specific finders
+ * }
+ *
+ * }
+ *
+ * @param The ID type
+ * @param + * This is equivalent to {@link DB#byName(String)} + * + * @param server The name of the Database. If this is null then the default Database is returned. + */ + public Database db(String server) { + return DB.byName(server); + } + + /** + * Creates an entity reference for this ID. + *
+ * Equivalent to {@link Database#getReference(Class, Object)}
+ */
+ @Nonnull
+ public T ref(I id) {
+ return db().getReference(type, id);
+ }
+
+ /**
+ * Retrieves an entity by ID.
+ */
+ @Nullable
+ public T findById(I id) {
+ return db().find(type, id);
+ }
+
+ /**
+ * Find an entity by ID returning an Optional.
+ */
+ @Nullable
+ public Optional
+ * Equivalent to {@link Database#update(Class)}
+ */
+ protected UpdateQuery
+ * Equivalent to {@link Database#find(Class)}
+ */
+ protected Query
+ *
+ * Typically users would extend BeanRepository rather than BeanFinder.
+ *
+ * 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.
+ *
+ *
+ * This would be used to specify a property that we did not wish to include in a stateless update.
+ *
+ * Ebean will detect if this is a new bean or a previously fetched bean and perform either an
+ * insert or an update based on that.
+ *
+ * @see Database#save(Object)
+ */
+ public void save(T bean) {
+ db().save(bean);
+ }
+
+ /**
+ * Save all the beans in the collection.
+ */
+ public int saveAll(Collection
+ * 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.
+ *
+ * This is used when the bean contains a
+ * Ebean will detect if this is a new bean or a previously fetched bean and perform either an
+ * insert or an update based on that.
+ *
+ * @see Database#merge(Object)
+ */
+ public void merge(T bean) {
+ db().merge(bean);
+ }
+
+ /**
+ * Merge this entity using the specified merge options.
+ *
+ * Ebean will detect if this is a new bean or a previously fetched bean and perform either an
+ * insert or an update based on that.
+ *
+ * @see Database#merge(Object, MergeOptions)
+ */
+ public void merge(T bean, MergeOptions options) {
+ db().merge(bean, options);
+ }
+
+ /**
+ * Refreshes this entity from the database.
+ *
+ * @see Database#refresh(Object)
+ */
+ public void refresh(T bean) {
+ db().refresh(bean);
+ }
+}
diff --git a/src/main/java/io/ebean/BeanState.java b/src/main/java/io/ebean/BeanState.java
index ddb76d358..da8c24d81 100644
--- a/src/main/java/io/ebean/BeanState.java
+++ b/src/main/java/io/ebean/BeanState.java
@@ -1,5 +1,6 @@
package io.ebean;
+import javax.annotation.Nullable;
import java.util.Map;
import java.util.Set;
@@ -56,7 +57,7 @@ public interface BeanState {
*
* // set loaded state on the email property to false so that
* // the email property is not included in a stateless update
- * Ebean.getBeanState(user).setPropertyLoaded("email", false);
+ * DB.getBeanState(user).setPropertyLoaded("email", false);
*
* user.update();
*
@@ -101,7 +102,7 @@ public interface BeanState {
/**
* Advanced - Used to programmatically build a partially or fully loaded
* entity bean. First create an entity bean via
- * {@link EbeanServer#createEntityBean(Class)}, then populate its properties
+ * {@link Database#createEntityBean(Class)}, then populate its properties
* and then call this method specifying which properties where loaded or null
* for a fully loaded entity bean.
*/
@@ -111,4 +112,10 @@ public interface BeanState {
* Reset the bean putting it into NEW state such that a save() results in an insert.
*/
void resetForInsert();
+
+ /**
+ * Returns a map with load erros.
+ */
+ @Nullable
+ Map
* This would be similar to using the
- *
diff --git a/src/main/java/io/ebean/CountDistinctOrder.java b/src/main/java/io/ebean/CountDistinctOrder.java
new file mode 100644
index 000000000..e23ac4fd4
--- /dev/null
+++ b/src/main/java/io/ebean/CountDistinctOrder.java
@@ -0,0 +1,27 @@
+package io.ebean;
+/**
+ * Enumeration to use with {@link Query#setCountDistinct(CountDistinctOrder)}.
+ * @author Roland Praml, FOCONIS AG
+ *
+ */
+public enum CountDistinctOrder {
+ NO_ORDERING,
+
+ /** order by attribute ascending */
+ ATTR_ASC,
+
+ /** order by attribute descending */
+ ATTR_DESC,
+
+ /** order by count ascending and attribute ascending */
+ COUNT_ASC_ATTR_ASC,
+
+ /** order by count ascending and attribute descending */
+ COUNT_ASC_ATTR_DESC,
+
+ /** order by count descending and attribute ascending */
+ COUNT_DESC_ATTR_ASC,
+
+ /** order by count descending and attribute descending */
+ COUNT_DESC_ATTR_DESC,
+}
diff --git a/src/main/java/io/ebean/CountedValue.java b/src/main/java/io/ebean/CountedValue.java
new file mode 100644
index 000000000..3752f8e51
--- /dev/null
+++ b/src/main/java/io/ebean/CountedValue.java
@@ -0,0 +1,33 @@
+package io.ebean;
+
+import java.io.Serializable;
+/**
+ * Holds a distinct value with it's count.
+ * (Used with {@link Query#findSingleAttributeList()} and {@link Query#setCountDistinct(CountDistinctOrder)}.)
+ * @author Roland Praml, FOCONIS AG
+ */
+public class CountedValue implements Serializable {
+ private static final long serialVersionUID = -2267971668356749695L;
+
+ private final A value;
+ private final long count;
+
+ public CountedValue(A value, long count) {
+ this.value = value;
+ this.count = count;
+ }
+
+ public long getCount() {
+ return count;
+ }
+
+ public A getValue() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ return count + ": " + value;
+ }
+
+}
diff --git a/src/main/java/io/ebean/DB.java b/src/main/java/io/ebean/DB.java
new file mode 100644
index 000000000..0379bae6d
--- /dev/null
+++ b/src/main/java/io/ebean/DB.java
@@ -0,0 +1,1254 @@
+package io.ebean;
+
+import io.ebean.annotation.TxIsolation;
+import io.ebean.cache.ServerCacheManager;
+import io.ebean.config.DatabaseConfig;
+import io.ebean.plugin.Property;
+import io.ebean.text.csv.CsvReader;
+import io.ebean.text.json.JsonContext;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.persistence.OptimisticLockException;
+import javax.persistence.PersistenceException;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+
+/**
+ * DB is a registry of {@link Database} by name.
+ *
+ * DB additionally provides a convenient way to use the 'default' Database.
+ *
+ *
+ * One of the Database instances can be registered as the "default database"
+ * and can be obtained using
+ * Multiple database instances can be registered with DB and we can obtain them
+ * using
+ * DB has methods like {@link #find(Class)} and {@link #save(Object)} which are
+ * just convenience for using the default database.
+ *
+ * The ExpressionFactory is used internally by the query and ExpressionList to
+ * build the WHERE and HAVING clauses. Alternatively you can use the
+ * ExpressionFactory directly to create expressions to add to the query where
+ * clause.
+ *
+ * Alternatively you can use the {@link Expr} as a shortcut to the
+ * ExpressionFactory of the 'Default' database.
+ *
+ * You generally need to the an ExpressionFactory (or {@link Expr}) to build
+ * an expression that uses OR like Expression e = Expr.or(..., ...);
+ *
+ * This will only work when a IdGenerator is on this bean type such as 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.
+ *
+ * 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.
+ *
+ * If we want to externalise the transaction management then we do this via Database.
+ * With Database we can pass the transaction to the various find(), save() and execute()
+ * methods. This gives us the ability to create the transactions externally from Ebean
+ * and use the transaction explicitly via the various methods available on Database.
+ *
+ * Note that this provides an try finally alternative to using {@link #executeCall(TxScope, Callable)} or
+ * {@link #execute(TxScope, Runnable)}.
+ *
+ *
+ * Flushing occurs automatically when:
+ *
+ * It is preferable to use try with resources rather than this.
+ *
+ * Useful to put in a finally block to ensure the transaction is ended, rather
+ * than a rollbackTransaction() in each catch block.
+ *
+ * Code example:
+ *
+ * When null is passed in for b, then the 'OldValues' of a is used for the
+ * difference comparison.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * This is used so that when a bean that is otherwise unmodified is updated with the version
+ * property 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.
+ *
+ * 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).
+ *
+ * {@link DatabaseConfig#setUpdatesDeleteMissingChildren(boolean)}: 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.
+ *
+ * {@link DatabaseConfig#setUpdateChangesOnly(boolean)}: The updateChangesOnly setting
+ * controls if only the changed properties are included in the update or if all the loaded
+ * properties are included instead.
+ *
+ * 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!
+ *
+ *
+ * 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 is configured with
+ * 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.
+ *
+ * Note that this resets OneToMany and ManyToMany properties so that if they
+ * are accessed a lazy load will refresh the many property.
+ *
+ * This is sometimes described as a proxy (with lazy loading).
+ *
+ * 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.
+ *
+ * If you want more control over the query then you can use createQuery() and
+ * Query.findOne();
+ *
+ * Refer to {@link DtoQuery} for native sql queries returning DTO beans.
+ *
+ * Refer to {@link #findNative(Class, String)} for native sql queries returning entity beans.
+ *
+ * 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.
+ *
+ * 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:
+ *
+ * For RawSql the named query is expected to be in ebean.xml.
+ *
+ * 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()} etc will execute against
+ * the same database from which is was created.
+ *
+ *
+ * This is actually the same as {@link #createQuery(Class)}. The reason it
+ * exists is that people used to JPA will probably be looking for a
+ * createQuery method (the same as entityManager).
+ *
+ * The native SQL can contain named parameters or positioned parameters.
+ *
+ * DTO beans are just normal bean like classes with public constructor(s) and setters.
+ * They do not need to be registered with Ebean before use.
+ *
+ *
+ * This produces and returns a new list with the sort and filters applied.
+ *
+ * Refer to {@link Filter} for an example of its use.
+ *
+// * If you wish to execute a Sql Select natively then you should use the
+// * FindByNativeSql object.
+// *
+// * 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:
+// *
+// * Example:
+// *
+ * The scope can control the transaction type, isolation and rollback
+ * semantics.
+ *
+ * The default scope runs with REQUIRED and by default will rollback on any
+ * exception (checked or runtime).
+ *
+ * The scope can control the transaction type, isolation and rollback
+ * semantics.
+ *
+ * The default scope runs with REQUIRED and by default will rollback on any
+ * exception (checked or runtime).
+ *
+ * This is basically the same as TxRunnable except that it returns an Object
+ * (and you specify the return type via generics).
+ *
+ * If you use DB.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).
+ *
+ * This will return null if the bean is not an enhanced entity bean.
+ *
+ * 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)}.
+ *
+ * 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.
+ *
+ * Database's are constructed by the DatabaseFactory. They can be created
+ * programmatically via {@link DatabaseFactory#create(DatabaseConfig)} or they
+ * can be automatically constructed on demand using configuration information in
+ * the application.properties file.
+ *
+ *
+ * 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.
+ *
+ * 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 deregistering the
+ * JDBC driver.
+ *
+ * This will return null if the bean is not an enhanced entity bean.
+ *
+ * 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.
+ *
+ * When null is passed in for b, then the 'OldValues' of a is used for the
+ * difference comparison.
+ *
+ * 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.
+ *
+ *
+ * For RawSql the named query is expected to be in ebean.xml.
+ *
+ *
+ * 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.
+ *
+ *
+ * The native SQL can contain named parameters or positioned parameters.
+ *
+ * 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.
+ *
+ * This produces and returns a new list with the sort and filters applied.
+ *
+ * Refer to {@link Filter} for an example of its use.
+ *
+ * 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.
+ *
+ *
+ * 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:
+ *
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * Refer to {@link DtoQuery} for native sql queries returning DTO beans.
+ *
+ * Refer to {@link #findNative(Class, String)} for native sql queries returning entity beans.
+ *
+ * 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.
+ *
+ * You will want to do this if you want multiple Transactions in a single
+ * thread or generally use transactions outside of the TransactionThreadLocal
+ * management.
+ *
+ * Note that this transaction is NOT stored in a thread local.
+ *
+ * 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.
+ *
+ *
+ *
+ *
+ *
+ * If you want to externalise the transaction management then you use
+ * createTransaction() and pass the transaction around to the various methods on
+ * Database yourself.
+ *
+ *
+ * Note that this provides an try finally alternative to using {@link #executeCall(TxScope, Callable)} or
+ * {@link #execute(TxScope, Runnable)}.
+ *
+ *
+ *
+ * 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
+ * Useful to put in a finally block to ensure the transaction is ended, rather
+ * than a rollbackTransaction() in each catch block.
+ *
+ * Code example:
+ *
+ *
+ * Note that this resets OneToMany and ManyToMany properties so that if they
+ * are accessed a lazy load will refresh the many property.
+ *
+ *
+ *
+ * If you want more control over the query then you can use createQuery() and
+ * Query.findOne();
+ *
+ *
+ * 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:
+ *
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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:
+ *
+ *
+ * This returns the number of rows that where inserted, updated or deleted.
+ *
+ * Example:
+ *
+ *
+ * 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).
+ *
+ * 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!
+ *
+ *
+ * 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.
+ *
+ *
+ * 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).
+ *
+ * {@link ServerConfig#setUpdatesDeleteMissingChildren(boolean)}: 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.
+ *
+ * {@link ServerConfig#setUpdateChangesOnly(boolean)}: The updateChangesOnly setting
+ * controls if only the changed properties are included in the update or if all the loaded
+ * properties are included instead.
+ *
+ *
+ * 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).
+ *
+ * The scope can control the transaction type, isolation and rollback
+ * semantics.
+ *
+ *
+ * The default scope runs with REQUIRED and by default will rollback on any
+ * exception (checked or runtime).
+ *
+ *
+ * The scope can control the transaction type, isolation and rollback
+ * semantics.
+ *
+ *
+ * The default scope runs with REQUIRED and by default will rollback on any
+ * exception (checked or runtime).
+ *
+ *
+ * This instance is safe to be used concurrently by multiple threads and this
+ * method is cheap to call.
+ *
+ *
+ *
+ * The values are published from the draft to the live bean.
+ *
+ * The values are published from the draft to the live bean.
+ *
+ * The values are published from the draft beans to the live beans.
+ *
+ * The values are published from the draft beans to the live beans.
+ *
+ * The values from the live beans are set back to the draft bean and the
+ *
+ * The values from the live beans are set back to the draft bean and the
+ *
+ * The values from the live beans are set back to the draft bean and the
+ *
+ * The values from the live beans are set back to the draft bean and the
+ *
+ * Validate the query checking the where and orderBy expression paths to confirm if
+ * they represent valid properties/path for the given bean type.
+ *
+ * This uses either DatabaseConfig or properties in the application.properties file to
+ * configure and create a Database instance.
+ *
+ * The Database instance can either be registered with the DB singleton or
+ * not. The DB singleton effectively holds a map of Database by a name.
+ * If the Database is registered with the DB singleton you can retrieve it
+ * later via {@link DB#byName(String)}.
+ *
+ * One Database can be nominated as the 'default/primary' Database. Many
+ * methods on the DB singleton such as {@link DB#find(Class)} are just a
+ * convenient way of using the 'default/primary' Database.
+ *
+ * Call this prior to creating any Database instances or alternatively set the
+ * ContainerConfig on the ServerConfig when creating the first Database instance.
+ */
+ public static synchronized void initialiseContainer(ContainerConfig containerConfig) {
+ EbeanServerFactory.initialiseContainer(containerConfig);
+ }
+
+ /**
+ * Create using ebean.properties to configure the server.
+ */
+ public static synchronized Database create(String name) {
+ return EbeanServerFactory.create(name);
+ }
+
+ /**
+ * Create using the ServerConfig object to configure the server.
+ */
+ public static synchronized Database create(DatabaseConfig config) {
+ return EbeanServerFactory.create(config);
+ }
+
+ /**
+ * Create using the ServerConfig additionally specifying a classLoader to use as the context class loader.
+ */
+ public static synchronized Database createWithContextClassLoader(DatabaseConfig config, ClassLoader classLoader) {
+ return EbeanServerFactory.createWithContextClassLoader(config, classLoader);
+ }
+
+ /**
+ * Shutdown gracefully all Database instances cleaning up any resources as required.
+ *
+ * This is typically invoked via JVM shutdown hook and not explicitly called.
+ *
+ * These beans are just normal classes. They must have public constructors
+ * and setters.
+ *
+ * Constructors with arguments are used if the number of constructor arguments
+ * matches the number of columns in the resultSet.
+ *
+ * If the number of columns in the resultSet is greater than the largest constructor
+ * then the largest constructor is used for the first columns and remaining columns
+ * are mapped by setter methods.
+ *
+ * This streaming type query is useful for large query execution as only 1 row needs to be held in memory.
+ *
+ * Returning false after processing a row stops the iteration through the query results.
+ *
+ * This streaming type query is useful for large query execution as only 1 row needs to be held in memory.
+ *
+ * This will typically result in a call to setQueryTimeout() on a
+ * preparedStatement. If the timeout occurs an exception will be thrown - this
+ * will be a SQLException wrapped up in a PersistenceException.
+ *
+ * Gives the JDBC driver a hint as to the number of rows that should be
+ * fetched from the database when more rows are needed for ResultSet.
+ *
- * If you are using a Dependency Injection framework such as
- * Spring or Guice you will probably
- * NOT use this Ebean singleton object. Instead you will
- * configure and construct EbeanServer instances using {@link ServerConfig} and
- * {@link EbeanServerFactory} and inject those EbeanServer instances into your
- * data access objects.
- *
- * In documentation "Ebean singleton" refers to this object.
- *
- * For developer convenience Ebean has static methods that proxy through to the
- * methods on the 'default' EbeanServer. These methods are provided for
- * developers who are mostly using a single database. Many developers will be
- * able to use the methods on Ebean rather than get a EbeanServer.
- *
- * EbeanServers can be created and used without ever needing or using the Ebean
- * singleton. Refer to {@link ServerConfig#setRegister(boolean)}.
- *
- * You can either programmatically create/register EbeanServers via
- * {@link EbeanServerFactory} or they can automatically be created and
- * registered when you first use the Ebean singleton. When EbeanServers are
- * created automatically they are configured using information in the
- * ebean.properties file.
- *
- * When you have multiple databases and need access to a specific one the
- * {@link #getServer(String)} method provides access to the EbeanServer for that
- * specific database.
- *
* This is provided to access EbeanServer for databases other than the
@@ -376,7 +299,7 @@ public final class Ebean {
* Note that this provides an try finally alternative to using {@link #executeCall(TxScope, Callable)} or
* {@link #execute(TxScope, Runnable)}.
*
*
+ * 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!
+ *
+ *
@@ -1043,10 +1045,9 @@ public final class Ebean {
*
* String sql = "select c.id, c.name from customer c where c.name like ? order by c.name";
*
- * Query
+ * DTO beans are just normal bean like classes with public constructor(s) and setters.
+ * They do not need to be registered with Ebean before use.
+ *
diff --git a/src/main/java/io/ebean/EbeanServer.java b/src/main/java/io/ebean/EbeanServer.java
index 4ca3e7c6b..6b56621f4 100644
--- a/src/main/java/io/ebean/EbeanServer.java
+++ b/src/main/java/io/ebean/EbeanServer.java
@@ -1,1853 +1,13 @@
package io.ebean;
-import io.ebean.annotation.TxIsolation;
-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 javax.annotation.Nonnull;
-import javax.annotation.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.concurrent.Callable;
-import java.util.function.Consumer;
-import java.util.function.Predicate;
-
/**
- * Provides the API for fetching and saving beans to a particular DataSource.
+ * Provides the API for fetching and saving beans to a particular Database.
*
- * Registration with the Ebean Singleton:
- * The 'default' EbeanServer
- * There is one EbeanServer per Database (javax.sql.DataSource). One EbeanServer
- * is referred to as the 'default' server and that is the one that
- * Ebean methods such as {@link Ebean#find(Class)} use.
- *
- * Constructing a EbeanServer
- * Example: Get a EbeanServer
- *
- *
- *
- * EbeanServer has more API than Ebean
- * External Transactions: 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).
- *
- * 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.
- *
- * 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 deregistering the
- * JDBC driver.
- *
- * This will return null if the bean is not an enhanced entity bean.
- *
- * 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.
- *
- * When null is passed in for b, then the 'OldValues' of a is used for the
- * difference comparison.
- *
- * 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.
- *
- *
- * For RawSql the named query is expected to be in ebean.xml.
- *
- *
- * 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 EbeanServer from
- * which is was created.
- *
- *
- * The native SQL can contain named parameters or positioned parameters.
- *
- * 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.
- *
- * This produces and returns a new list with the sort and filters applied.
- *
- * Refer to {@link Filter} for an example of its use.
- *
- * 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.
- *
- *
- * 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:
- *
- *
- * Note that you can use raw SQL with entity beans, refer to the SqlSelect
- * annotation for examples.
- *
- * 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.
- *
- * You will want to do this if you want multiple Transactions in a single
- * thread or generally use transactions outside of the TransactionThreadLocal
- * management.
- *
- * Note that this transaction is NOT stored in a thread local.
- *
- * 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.
- *
- *
- *
- *
- * If you want to externalise the transaction management then you use
- * createTransaction() and pass the transaction around to the various methods on
- * EbeanServer yourself.
- *
- *
- * Note that this provides an try finally alternative to using {@link #executeCall(TxScope, Callable)} or
- * {@link #execute(TxScope, Runnable)}.
- *
- *
- *
- * 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
- * Useful to put in a finally block to ensure the transaction is ended, rather
- * than a rollbackTransaction() in each catch block.
- *
- * Code example:
- *
- *
- *
- * Note that this resets OneToMany and ManyToMany properties so that if they
- * are accessed a lazy load will refresh the many property.
- *
- *
- *
- * If you want more control over the query then you can use createQuery() and
- * Query.findOne();
- *
- *
- * 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:
- *
- *
- * 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).
- *
- * 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.
- *
- * 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.
- *
- * Internally this query using a PersistenceContext scoped to each bean (and the
- * beans associated object graph).
- *
- *
- * Compared to findEach() this provides the ability to stop processing the query
- * results early by returning false for the Predicate.
- *
- * 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.
- *
- * Internally this query using a PersistenceContext scoped to each bean (and the
- * beans associated object graph).
- *
- *
- * 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.
- *
- * 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.
- *
- *
- * 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).
- *
- * 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).
- *
- * 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).
- *
- * 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()
- */
- @Nonnull
- {@code
+ *
+ * int rows =
+ * updateQuery()
+ * .set("status", Customer.Status.ACTIVE)
+ * .set("updtime", new Timestamp(System.currentTimeMillis()))
+ * .where()
+ * .gt("id", 1000)
+ * .update();
+ *
+ * }
+ *
+ * {@code
+ *
+ * @Repository
+ * public class CustomerRepository extends BeanRepository
+ *
+ * @param The ID type
+ * @param {@code
+ *
+ * @Inject
+ * public CustomerRepository(Database server) {
+ * super(Customer.class, server);
+ * }
+ *
+ * }
+ *
+ * @param type The bean type
+ * @param server The Database instance typically created via Spring factory or equivalent
+ */
+ protected BeanRepository(Class{@code
+ *
+ * Customer customer = customerRepository.byId(id);
+ *
+ * // mark the bean as dirty so that a save() or update() will
+ * // increment the version property
+ *
+ * customerRepository.markAsDirty(customer);
+ * customerRepository.save(customer);
+ *
+ * }
+ *
+ * @see Database#markAsDirty(Object)
+ */
+ public void markAsDirty(T bean) {
+ db().markAsDirty(bean);
+ }
+
+ /**
+ * Mark the property as unset or 'not loaded'.
+ * {@code
+ *
+ * // populate an entity bean from JSON or whatever
+ * Customer customer = ...;
+ *
+ * // mark the email property as 'unset' so that it is not
+ * // included in a 'stateless update'
+ * customerRepository.markPropertyUnset(customer, "email");
+ *
+ * customerRepository.update(customer);
+ *
+ * }
+ *
+ * @param propertyName the name of the property on the bean to be marked as 'unset'
+ */
+ public void markPropertyUnset(T bean, String propertyName) {
+ ((EntityBean) bean)._ebean_getIntercept().setPropertyLoaded(propertyName, false);
+ }
+
+ /**
+ * Insert or update this entity depending on its state.
+ * @SoftDelete property and we
+ * want to perform a hard/permanent delete.
+ * Ebean.externalModification() method. It may be easier and make
+ * DB.externalModification() method. It may be easier and make
* more sense to set it here with the CallableSql.
* Default database
+ * DB.getDefault()
+ * {@code
+ *
+ * Database database = DB.getDefault();
+ *
+ * }
+ *
+ * Named database
+ * DB.byName()
+ * {@code
+ *
+ * Database hrDatabase = DB.byName("hr");
+ *
+ * }
+ *
+ * Convenience methods
+ * {@code
+ *
+ * // fetch using the default database
+ * Order order = DB.find(Order.class, 10);
+ *
+ * // is the same as
+ * Database database = DB.getDefault();
+ * Order order = database.find(Order.class, 10);
+ *
+ * }
+ */
+public class DB {
+
+ /**
+ * Hide constructor.
+ */
+ private DB() {
+ }
+
+ /**
+ * Return the default database.
+ */
+ public static Database getDefault() {
+ return Ebean.getDefaultServer();
+ }
+
+ /**
+ * Return the database for the given name.
+ *
+ * @param name The name of the database
+ */
+ public static Database byName(String name) {
+ return Ebean.getServer(name);
+ }
+
+// /**
+// * Register the server with this Ebean singleton. Specify if the registered
+// * server is the primary/default server.
+// */
+// public static void register(EbeanServer server, boolean defaultServer) {
+// serverMgr.register(server, defaultServer);
+// }
+//
+// /**
+// * Backdoor for registering a mock implementation of EbeanServer as the default server.
+// */
+// protected static EbeanServer mock(String name, EbeanServer server, boolean defaultServer) {
+// EbeanServer originalPrimaryServer = serverMgr.defaultServer;
+// serverMgr.registerWithName(name, server, defaultServer);
+// return originalPrimaryServer;
+// }
+
+ /**
+ * Return the ExpressionFactory from the default database.
+ * {@code
+ *
+ * try (Transaction transaction = DB.beginTransaction()) {
+ *
+ * Order order = DB.find(Order.class, 42);
+ * order.setStatus(Status.COMPLETE);
+ * order.save();
+ *
+ * transaction.commit();
+ * }
+ *
+ * }
+ * REQUIRES_NEW example:
+ * {@code
+ * // Start a new transaction. If there is a current transaction
+ * // suspend it until this transaction ends
+ *
+ * try (Transaction txn = DB.beginTransaction(TxScope.requiresNew())) {
+ * ...
+ *
+ * // commit the transaction
+ * txn.commit();
+ * }
+ * }
+ *
+ * REQUIRED example:
+ * {@code
+ * // start a new transaction if there is not a current transaction
+ *
+ * try (Transaction txn = DB.beginTransaction(TxScope.required())) {
+ * ...
+ *
+ * // commit the transaction if it was created or
+ * // do nothing if there was already a current transaction
+ * txn.commit();
+ * }
+ * }
+ */
+ public static Transaction beginTransaction(TxScope scope) {
+ return getDefault().beginTransaction(scope);
+ }
+
+ /**
+ * Returns the current transaction or null if there is no current transaction in scope.
+ */
+ public static Transaction currentTransaction() {
+ return getDefault().currentTransaction();
+ }
+
+ /**
+ * The batch will be flushing automatically but you can use this to explicitly
+ * flush the batch if you like.
+ *
+ *
+ */
+ public static void flush() {
+ currentTransaction().flush();
+ }
+
+ /**
+ * 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
+ */
+ public static void register(TransactionCallback transactionCallback) throws PersistenceException {
+ getDefault().register(transactionCallback);
+ }
+
+ /**
+ * Commit the current transaction.
+ */
+ public static void commitTransaction() {
+ getDefault().commitTransaction();
+ }
+
+ /**
+ * Rollback the current transaction.
+ */
+ public static void rollbackTransaction() {
+ getDefault().rollbackTransaction();
+ }
+
+ /**
+ * If the current transaction has already been committed do nothing otherwise
+ * rollback the transaction.
+ * {@code
+ * DB.beginTransaction();
+ * try {
+ * // do some fetching and or persisting
+ *
+ * // commit at the end
+ * DB.commitTransaction();
+ *
+ * } finally {
+ * // if commit didn't occur then rollback the transaction
+ * DB.endTransaction();
+ * }
+ * }
+ */
+ public static void endTransaction() {
+ getDefault().endTransaction();
+ }
+
+ /**
+ * Mark the current transaction as rollback only.
+ */
+ public static void setRollbackOnly() {
+ getDefault().currentTransaction().setRollbackOnly();
+ }
+
+ /**
+ * Return a map of the differences between two objects of the same type.
+ * {@code
+ *
+ * Customer customer = DB.find(Customer, id);
+ *
+ * // mark the bean as dirty so that a save() or update() will
+ * // increment the version property
+ * DB.markAsDirty(customer);
+ * DB.save(customer);
+ *
+ * }
+ */
+ public static void markAsDirty(Object bean) throws OptimisticLockException {
+ getDefault().markAsDirty(bean);
+ }
+
+ /**
+ * Saves the bean using an update. If you know you are updating a bean then it is preferrable to
+ * use this update() method rather than save().
+ * {@code
+ *
+ * // A 'stateless update' example
+ * Customer customer = new Customer();
+ * customer.setId(7);
+ * customer.setName("ModifiedNameNoOCC");
+ * database.update(customer);
+ *
+ * }
+ *
+ * @see DatabaseConfig#setUpdatesDeleteMissingChildren(boolean)
+ * @see DatabaseConfig#setUpdateChangesOnly(boolean)
+ */
+ public static void update(Object bean) throws OptimisticLockException {
+ getDefault().update(bean);
+ }
+
+ /**
+ * Update the beans in the collection.
+ */
+ public static void updateAll(Collection> beans) throws OptimisticLockException {
+ getDefault().updateAll(beans);
+ }
+
+ /**
+ * Merge the bean using the default merge options.
+ *
+ * @param bean The bean to merge
+ */
+ public static void merge(Object bean) {
+ getDefault().merge(bean);
+ }
+
+ /**
+ * Merge the bean using the given merge options.
+ *
+ * @param bean The bean to merge
+ * @param options The options to control the merge
+ */
+ public static void merge(Object bean, MergeOptions options) {
+ getDefault().merge(bean, options);
+ }
+
+ /**
+ * Save all the beans from a Collection.
+ */
+ public static int saveAll(Collection> beans) throws OptimisticLockException {
+ return getDefault().saveAll(beans);
+ }
+
+ /**
+ * 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.
+ * {@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
+ *
+ * @param bean The entity bean to check uniqueness on
+ * @return a set of Properties if constraint validation was detected or empty list.
+ */
+ @Nonnull
+ public static Set@SoftDelete then this will perform a soft
+ * delete rather than a hard/permanent delete.
+ * {@code
+ *
+ * Order order = ...;
+ * ...
+ * // refresh the order details...
+ * DB.refreshMany(order, "details");
+ *
+ * }
+ *
+ * @param bean the entity bean containing the List Set or Map to refresh.
+ * @param manyPropertyName the property name of the List Set or Map to refresh.
+ */
+ public static void refreshMany(Object bean, String manyPropertyName) {
+ getDefault().refreshMany(bean, manyPropertyName);
+ }
+
+ /**
+ * Get a reference object.
+ * {@code
+ *
+ * Product product = DB.getReference(Product.class, 1);
+ *
+ * // You can get the id without causing a fetch/lazy load
+ * Integer 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
+ */
+ public static
+ *
+ * {@code
+ *
+ * // find orders and their customers
+ * List
+ *
+ * @param list the list of entity beans
+ * @param sortByClause the properties to sort the list by
+ */
+ public static {@code
+ *
+ * // Fetch order 1
+ * Order order = DB.find(Order.class, 1);
+ *
+ * }
+ * {@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
+ *
+ * @param beanType the type of entity bean to fetch
+ * @param id the id value
+ */
+ @Nullable
+ public static {@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
+ */
+ public static Example
+ * {@code
+ *
+ * // Find order additionally fetching the customer, details and details.product name.
+ *
+ * String eql = "fetch customer fetch details fetch details.product (name) where id = :orderId ";
+ *
+ * Query
+ *
+ * @param beanType The type of bean to fetch
+ * @param eql The Ebean query
+ * @param {@code
+ *
+ * String sql = "select c.id, c.name from customer c where c.name like ? order by c.name";
+ *
+ * Query
+ *
+ * @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
+ */
+ public static {@code
+ *
+ * int rows = DB.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 {@code
+// *
+// * // example that uses 'named' parameters
+// * String s = "UPDATE f_topic set post_count = :count where id = :id"
+// *
+// * SqlUpdate update = DB.createSqlUpdate(s);
+// *
+// * update.setParameter("id", 1);
+// * update.setParameter("count", 50);
+// *
+// * int modifiedCount = DB.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 SqlUpdate
+// * @see CallableSql
+// * @see DB#execute(CallableSql)
+// */
+// public static int execute(SqlUpdate sqlUpdate) {
+// return defaultDatabase().execute(sqlUpdate);
+// }
+//
+// /**
+// * For making calls to stored procedures.
+// * {@code
+// *
+// * String sql = "{call sp_order_modify(?,?,?)}";
+// *
+// * CallableSql cs = DB.createCallableSql(sql);
+// * cs.setParameter(1, 27);
+// * cs.setParameter(2, "SHIPPED");
+// * cs.registerOut(3, Types.INTEGER);
+// *
+// * DB.execute(cs);
+// *
+// * // read the out parameter
+// * Integer returnValue = (Integer) cs.getObject(3);
+// *
+// * }
+// *
+// * @see CallableSql
+// * @see Ebean#execute(SqlUpdate)
+// */
+// public static int execute(CallableSql callableSql) {
+// return defaultDatabase().execute(callableSql);
+// }
+
+ /**
+ * Execute a TxRunnable in a Transaction with an explicit scope.
+ * {@code
+ *
+ * // set specific transactional scope settings
+ * TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
+ *
+ * DB.execute(scope, new TxRunnable() {
+ * public void run() {
+ * User u1 = DB.find(User.class, 1);
+ * ...
+ * }
+ * });
+ *
+ * }
+ */
+ public static void execute(TxScope scope, Runnable r) {
+ getDefault().execute(scope, r);
+ }
+
+ /**
+ * Execute a Runnable in a Transaction with the default scope.
+ * {@code
+ *
+ * DB.execute(() -> {
+ *
+ * User u1 = DB.find(User.class, 1);
+ * User u2 = DB.find(User.class, 2);
+ *
+ * u1.setName("u1 mod");
+ * u2.setName("u2 mod");
+ *
+ * DB.save(u1);
+ * DB.save(u2);
+ * });
+ * }
+ */
+ public static void execute(Runnable r) {
+ getDefault().execute(r);
+ }
+
+ /**
+ * Execute a Callable in a Transaction with an explicit scope.
+ * {@code
+ *
+ * // set specific transactional scope settings
+ * TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
+ *
+ * DB.executeCall(scope, new Callable
+ */
+ public static {@code
+ *
+ * DB.executeCall(() -> {
+ *
+ * User u1 = DB.find(User.class, 1);
+ * User u2 = DB.find(User.class, 2);
+ *
+ * u1.setName("u1 mod");
+ * u2.setName("u2 mod");
+ *
+ * DB.save(u1);
+ * DB.save(u2);
+ *
+ * return u1.getEmail();
+ * });
+ * }
+ */
+ public static Registration with the DB singleton
+ * The 'default' Database
+ * Constructing a Database
+ * 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
+ * {@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 Example
+ * {@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
+ *
+ * @param beanType The type of bean to fetch
+ * @param ormQuery The Ebean ORM query
+ * @param {@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
+ */
+ {@code
+ *
+ * String sql = "select c.id, c.name from customer c where c.name like ? order by c.name";
+ *
+ * Query
+ *
+ * @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
+ */
+
+ *
+ * {@code
+ *
+ * // find orders and their customers
+ * List
+ *
+ * @param list the list of entity beans
+ * @param sortByClause the properties to sort the list by
+ */
+ {@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
+ */
+ 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();
+ * }
+ *
+ * }
+ * 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.
+ * currentTransaction().flush().
+ * {@code
+ *
+ * database.beginTransaction();
+ * try {
+ * // do some fetching and or persisting ...
+ *
+ * // commit at the end
+ * database.commitTransaction();
+ *
+ * } finally {
+ * // if commit didn't occur then rollback the transaction
+ * database.endTransaction();
+ * }
+ *
+ * }
+ */
+ void endTransaction();
+
+ /**
+ * Refresh the values of a bean.
+ * {@code
+ * // Fetch order 1
+ * Order order = database.find(Order.class, 1);
+ * }
+ * {@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
+ *
+ * @param beanType the type of entity bean to fetch
+ * @param id the id value
+ */
+ @Nullable
+ {@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
+ */
+ @Nonnull
+ {@code
+ * public class Order { ...
+ *
+ * @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
+ * List
+ * {@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.
+ * {@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.
+ * {@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
+ *
+ * @param bean The entity bean to check uniqueness on
+ * @return a set of Properties if constraint validation was detected or empty list.
+ */
+ @Nonnull
+ Set{@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().
+ * {@code
+ *
+ * // A 'stateless update' example
+ * Customer customer = new Customer();
+ * customer.setId(7);
+ * customer.setName("ModifiedNameNoOCC");
+ * database.update(customer);
+ *
+ * }
+ *
+ * @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;
+
+ /**
+ * 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.
+ * {@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.
+ * {@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.
+ * {@code
+ *
+ * // set specific transactional scope settings
+ * TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
+ *
+ * database.executeCall(scope, new Callable
+ */
+ {@code
+ *
+ * database.executeCall(new Callable
+ */
+ 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
+ *
+ * @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();
+
+ /**
+ * Return the Document store.
+ */
+ DocumentStore docStore();
+
+ /**
+ * Publish a single bean given its type and id returning the resulting live bean.
+ * @DraftDirty and @DraftReset properties are reset.
+ * @DraftDirty and @DraftReset properties are reset.
+ * @DraftDirty and @DraftReset properties are reset.
+ * @DraftDirty and @DraftReset properties are reset.
+ * {@code
+ *
+ * // CustomerDto is just a 'bean like' class
+ * // with public constructor(s) and public setter methods
+ *
+ * String sql = "select id, name from customer where name like :name and status_code = :status";
+ *
+ * List
+ */
+public interface DtoQuery
- *
- * {@code
- *
- * // fetch shipped orders (and also their customer)
- * List
- * {@code
- *
- * // fetch order 10, modify and save
- * Order order = Ebean.find(Order.class, 10);
- *
- * OrderStatus shipped = Ebean.getReference(OrderStatus.class,"SHIPPED");
- * order.setStatus(shipped);
- * order.setShippedDate(shippedDate);
- * ...
- *
- * // implicitly creates a transaction and commits
- * Ebean.save(order);
- *
- * }
- * {@code
- *
- * // Get access to the Human Resources EbeanServer/Database
- * EbeanServer hrDb = Ebean.getServer("hr");
- *
- * // fetch contact 3 from the HR database
- * Contact contact = hrDb.find(Contact.class, 3);
- *
- * contact.setName("I'm going to change");
- * ...
- *
- * // save the contact back to the HR database
- * hrDb.save(contact);
- *
- * }
+ * The preference is to use DB and Database rather than Ebean and EbeanServer.
*/
public final class Ebean {
private static final Logger logger = LoggerFactory.getLogger(Ebean.class);
+ static {
+ EbeanVersion.getVersion(); // initialises the version class and logs the version.
+ }
+
/**
- * Manages creation and cache of EbeanServers.
+ * Manages creation and cache of Databases.
*/
private static final Ebean.ServerManager serverMgr = new Ebean.ServerManager();
/**
- * Helper class for managing fast and safe access and creation of
- * EbeanServers.
+ * Helper class for managing fast and safe access and creation of Databases.
*/
private static final class ServerManager {
@@ -131,29 +53,21 @@ public final class Ebean {
private final ConcurrentHashMapREQUIRES_NEW example:
* {@code
* // Start a new transaction. If there is a current transaction
@@ -621,7 +544,8 @@ public final class Ebean {
* Customer customer = new Customer();
* customer.setId(7);
* customer.setName("ModifiedNameNoOCC");
- * ebeanServer.update(customer);
+ *
+ * DB.update(customer);
*
* }
*
@@ -639,6 +563,25 @@ public final class Ebean {
serverMgr.getDefaultServer().updateAll(beans);
}
+ /**
+ * Merge the bean using the default merge options.
+ *
+ * @param bean The bean to merge
+ */
+ public static void merge(Object bean) {
+ serverMgr.getDefaultServer().merge(bean);
+ }
+
+ /**
+ * Merge the bean using the given merge options.
+ *
+ * @param bean The bean to merge
+ * @param options The options to control the merge
+ */
+ public static void merge(Object bean, MergeOptions options) {
+ serverMgr.getDefaultServer().merge(bean, options);
+ }
+
/**
* Save all the beans from a Collection.
*/
@@ -646,6 +589,65 @@ public final class Ebean {
return serverMgr.getDefaultServer().saveAll(beans);
}
+ /**
+ * 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.
+ * {@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
+ *
+ * @param bean The entity bean to check uniqueness on
+ * @return a set of Properties if constraint validation was detected or empty list.
+ */
+ @Nonnull
+ public static Set
- * 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)}.
- *
- * 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.
- *
- * 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.
- * {@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);
- * }
- *
- * 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.
- * {@code
- *
- * int rows = ebeanServer
- * .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 Example
- * {@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
- *
- * @param beanType The type of bean to fetch
- * @param ormQuery The Ebean ORM query
- * @param {@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)
- * .findOne();
- *
- * // find some new orders ... with firstRow/maxRows
- * List
- */
- {@code
- *
- * String sql = "select c.id, c.name from customer c where c.name like ? order by c.name";
- *
- * Query
- *
- * @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
- */
-
- *
- * {@code
- *
- * // find orders and their customers
- * List
- *
- * @param list the list of entity beans
- * @param sortByClause the properties to sort the list by
- */
- {@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
- */
- {@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();
- * }
- *
- * }
- * Transaction options:
- * {@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();
- * }
- *
- * }
- * REQUIRES_NEW example:
- * {@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();
- * }
- *
- * }
- * REQUIRED example:
- * {@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();
- * }
- *
- * }
- */
- 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.
- * currentTransaction().flush().
- * {@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();
- * }
- *
- * }
- * {@code
- * // Fetch order 1
- * Order order = ebeanServer.find(Order.class, 1);
- * }
- * {@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
- *
- * @param beanType the type of entity bean to fetch
- * @param id the id value
- */
- @Nullable
- {@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);
- *
- *
- * }
- * Lazy loading characteristics
- * {@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();
- *
- * }
- *
- * @param beanType the type of entity bean
- * @param id the id value
- */
- @Nonnull
- {@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);
- * });
- *
- * }
- *
- * @see Query#findEach(Consumer)
- * @see Query#findEachWhile(Predicate)
- */
- {@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;
- * });
- *
- * }
- *
- * @see Query#findEach(Consumer)
- * @see Query#findEachWhile(Predicate)
- */
- {@code
- *
- * List
- *
- * @param