package io.ebean; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.persistence.NonUniqueResultException; import java.sql.Connection; import java.sql.Timestamp; 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; import java.util.stream.Stream; /** * Object relational query for finding a List, Set, Map or single entity bean. *
* Example: Create the query using the API. *
**
{@code
*
* List orderList = DB.find(Order.class)
* .where()
* .like("customer.name","rob%")
* .gt("orderDate",lastWeek)
* .order("customer.id, id desc")
* .setMaxRows(50)
* .findList();
*
* ...
* }
* * Example: The same query using the query language *
*{@code
*
* String oql =
* +" where customer.name like :custName and orderDate > :minOrderDate "
* +" order by customer.id, id desc "
* +" limit 50 ";
*
* List orderList = DB.createQuery(Order.class, oql)
* .setParameter("custName", "Rob%")
* .setParameter("minOrderDate", lastWeek)
* .findList();
* ...
* }
* * Ebean has built in support for "AutoTune". This is a mechanism where a query * can be automatically tuned based on profiling information that is collected. *
** This is effectively the same as automatically using select() and fetch() to * build a query that will fetch all the data required by the application and no * more. *
** It is expected that AutoTune will be the default approach for many queries * in a system. It is possibly not as useful where the result of a query is sent * to a remote client or where there is some requirement for "Read Consistency" * guarantees. *
** Partial Objects *
** The find and fetch clauses support specifying a list of * properties to fetch. This results in objects that are "partially populated". * If you try to get a property that was not populated a "lazy loading" query * will automatically fire and load the rest of the properties of the bean (This * is very similar behaviour as a reference object being "lazy loaded"). *
** Partial objects can be saved just like fully populated objects. If you do * this you should remember to include the "Version" property in the * initial fetch. If you do not include a version property then optimistic * concurrency checking will occur but only include the fetched properties. * Refer to "ALL Properties/Columns" mode of Optimistic Concurrency checking. *
*{@code
* [ select [ ( * | {fetch properties} ) ] ]
* [ fetch {path} [ ( * | {fetch properties} ) ] ]
* [ where {predicates} ]
* [ order by {order by properties} ]
* [ limit {max rows} [ offset {first row} ] ]
* }
* * SELECT [ ( * | {fetch properties} ) ] *
** With the select you can specify a list of properties to fetch. *
** FETCH {path} [ ( * | {fetch properties} ) ] *
** With the fetch you specify the associated property to fetch and populate. The * path is a OneToOne, ManyToOne, OneToMany or ManyToMany property. *
** For fetch of a path we can optionally specify a list of properties to fetch. * If you do not specify a list of properties ALL the properties for that bean * type are fetched. *
** WHERE {list of predicates} *
** The list of predicates which are joined by AND OR NOT ( and ). They can * include named (or positioned) bind parameters. These parameters will need to * be bound by {@link Query#setParameter(String, Object)}. *
** ORDER BY {order by properties} *
** The list of properties to order the result. You can include ASC (ascending) * and DESC (descending) in the order by clause. *
** LIMIT {max rows} [ OFFSET {first row} ] *
** The limit offset specifies the max rows and first row to fetch. The offset is * optional. *
** Find orders fetching its id, shipDate and status properties. Note that the id * property is always fetched even if it is not included in the list of fetch * properties. *
*{@code
*
* select (shipDate, status)
*
* }
* * Find orders with a named bind variable (that will need to be bound via * {@link Query#setParameter(String, Object)}). *
*{@code
*
* where customer.name like :custLike
*
* }
* * Find orders and also fetch the customer with a named bind parameter. This * will fetch and populate both the order and customer objects. *
*{@code
*
* fetch customer
* where customer.id = :custId
*
* }
* * Find orders and also fetch the customer, customer shippingAddress, order * details and related product. Note that customer and product objects will be * "Partial Objects" with only some of their properties populated. The customer * objects will have their id, name and shipping address populated. The product * objects (associated with each order detail) will have their id, sku and name * populated. *
*{@code
*
* fetch customer (name)
* fetch customer.shippingAddress
* fetch details
* fetch details.product (sku, name)
*
* }
*
* @param * To perform this query the DB must have underlying history tables. *
* * @param asOf the date time in the past at which you want to view the data */ Query
* We effectively use the underlying ORM query to build the SQL and then execute
* and map it into DTO beans.
*/
* Typically this is used with query beans to covert a query bean
* query into an UpdateQuery like the examples below.
*
* This must be called from a different thread to the query executor.
*
* This is so that you can use a Query as a "prototype" for creating other
* query instances. You could create a Query with various where expressions
* and use that as a "prototype" - using this copy() method to create a new
* instance that you can then add other expressions then execute.
*
* For example, when executing a query against ElasticSearch with daily indexes we can
* explicitly specify the indexes to search against.
*
* If the indexName is specified with ${daily} e.g. "logstash-${daily}" ... then we can use
* $today and $last-x as the search docIndexName like the examples below.
*
* If you do not call this method on a query the "Implicit AutoTune mode" is
* used to determine if AutoTune should be used for a given query.
*
* AutoTune can add additional fetch paths to the query and specify which
* properties are included for each path. If you have explicitly defined some
* fetch paths AutoTune will not remove them.
*
* When lazy loading is invoked on beans loaded by this query then this sets the
* batch size used to load those beans.
*
* @param lazyLoadBatchSize the number of beans to lazy load in a single batch
*/
Query
* This means that Ebean will not add any predicates to the query for filtering out
* soft deleted rows. You can still add your own predicates for the deleted properties
* and effectively you have full control over the query to include or exclude soft deleted
* rows as needed for a given use case.
*
* This is intended to be used when the query is not a user initiated query and instead
* part of the internal processing in an application to load a cache or document store etc.
* In these cases we don't want the query to be part of read auditing.
*
* The Id property is automatically included in the properties to fetch unless setDistinct(true)
* is set on the query.
*
* Use {@link #fetch(String, String)} to specify specific properties to fetch
* on other non-root level paths of the object graph.
*
* Ebean will endeavour to fetch this path using a SQL join. If Ebean determines that it can
* not use a SQL join (due to maxRows or because it would result in a cartesian product) Ebean
* will automatically convert this fetch query into a "query join" - i.e. use fetchQuery().
*
* If columns is null or "*" then all columns/properties for that path are fetched.
*
* This is the same as:
*
* This would be used instead of a fetch() when we use a separate SQL query to fetch this
* part of the object graph rather than a SQL join.
*
* We might typically get a performance benefit when the path to fetch is a OneToMany
* or ManyToMany, the 'width' of the 'root bean' is wide and the cardinality of the many
* is high.
*
* This is the same as:
*
* The reason for using fetchLazy() is to either:
*
* Ebean will endeavour to fetch this path using a SQL join. If Ebean determines that it can
* not use a SQL join (due to maxRows or because it would result in a cartesian product) Ebean
* will automatically convert this fetch query into a "query join" - i.e. use fetchQuery().
*
* This is the same as:
*
* This would be used instead of a fetch() when we use a separate SQL query to fetch this
* part of the object graph rather than a SQL join.
*
* We might typically get a performance benefit when the path to fetch is a OneToMany
* or ManyToMany, the 'width' of the 'root bean' is wide and the cardinality of the many
* is high.
*
* This is the same as:
*
* The reason for using fetchLazy() is to either:
*
* This is typically used when the FetchPath is applied to both the query and the JSON output.
*
* This query will execute against the Database that was used to create it.
*
* Note that findIterate (and findEach and findEachWhile) uses a "per graph"
* persistence context scope and adjusts jdbc fetch buffer size for large
* queries. As such it is better to use findList for small queries.
*
* Remember that with {@link QueryIterator} you must call {@link QueryIterator#close()}
* when you have finished iterating the results (typically in a finally block).
*
* findEach() and findEachWhile() are preferred to findIterate() as they ensure
* the jdbc statement and resultSet are closed at the end of the iteration.
*
* This query will execute against the Database that was used to create it.
*
* Note that this can support very large queries iterating
* any number of results. To do so internally it can use
* multiple persistence contexts.
*
* Execute the query returning the result as a Stream.
*
* Note that this uses multiple persistence contexts such that we can use
* it with a large number of results.
*
* This method is appropriate to process very large query results as the
* beans are consumed one at a time and do not need to be held in memory
* (unlike #findList #findSet etc)
*
* Note that findEach (and findEachWhile and findIterate) uses a "per graph"
* persistence context scope and adjusts jdbc fetch buffer size for large
* queries. As such it is better to use findList for small queries.
*
* Note that internally Ebean can inform the JDBC driver that it is expecting larger
* resultSet and specifically for MySQL this hint is required to stop it's JDBC driver
* from buffering the entire resultSet. As such, for smaller resultSets findList() is
* generally preferable.
*
* Compared with #findEachWhile this will always process all the beans where as
* #findEachWhile provides a way to stop processing the query result early before
* all the beans have been read.
*
* This method is functionally equivalent to findIterate() but instead of using an
* iterator uses the Consumer interface which is better suited to use with closures.
*
* This query execution will stream the results and is suited to consuming
* large numbers of results from the database.
*
* Typically we use this batch consumer when we want to do further processing on
* the beans and want to do that processing in batch form, for example - 100 at
* a time.
*
* @param batch The number of beans processed in the batch
* @param consumer Process the batch of beans
*/
void findEach(int batch, Consumer
* Note that findEachWhile (and findEach and findIterate) uses a "per graph"
* persistence context scope and adjusts jdbc fetch buffer size for large
* queries. As such it is better to use findList for small queries.
*
* This method is functionally equivalent to findIterate() but instead of using an
* iterator uses the Predicate interface which is better suited to use with closures.
*
* This query will execute against the Database that was used to create it.
*
* This query will execute against the Database that was used to create it.
*
* This query will execute against the Database that was used to create it.
*
* You can use setMapKey() so specify the property values to be used as keys
* on the map. If one is not specified then the id property is used.
*
*
*
*
* The query is executed using max rows of 1 and will only select the id property.
* This method is really just a convenient way to optimise a query to perform a
* 'does a row exist in the db' check.
*
* If more than 1 row is found for this query then a NonUniqueResultException is
* thrown.
*
* This is useful when your predicates dictate that your query should only
* return 0 or 1 results.
*
* It is also useful with finding objects by their id when you want to specify
* further join information.
*
* Note that this query will work against view based history implementations
* but not sql2011 standards based implementations that require a start and
* end timestamp to be specified.
*
* 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 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.
*
* Note that if the query includes joins then the generated delete statement may not be
* optimal depending on the database platform.
*
* Note that if the query includes joins then the generated delete statement may not be
* optimal depending on the database platform.
*
* This is the number of 'top level' or 'root level' entities.
*
* 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.
*
* The benefit of using this over findList() is that it provides functionality to get the
* total row count etc.
*
* If maxRows is not set on the query prior to calling findPagedList() then a
* PersistenceException is thrown.
*
* A convenience for multiple calls to {@link #setParameter(Object)}
*/
Query
* You can use this to have further control over the query. For example adding
* fetch joins.
*
* This is currently ElasticSearch only and provides the full text
* expressions such as Match and Multi-Match.
*
* This automatically makes this query a "Doc Store" query and will execute
* against the document store (ElasticSearch).
*
* Expressions added here are added to the "query" section of an ElasticSearch
* query rather than the "filter" section.
*
* Expressions added to the where() are added to the "filter" section of an
* ElasticSearch query.
*
* Typically you will use this in a scenario where the cardinality is high on
* the 'many' property you wish to join to. Say you want to fetch customers
* and their associated orders... but instead of getting all the orders for
* each customer you only want to get the new orders they placed since last
* week. In this case you can use filterMany() to filter the orders.
*
* Please note you have to be careful that you add expressions to the correct
* expression list - as there is one for the 'root level' and one for each
* filterMany that you have.
*
* Currently only beans based on raw sql will use the having clause.
*
* Note that this returns the ExpressionList (so you can add multiple
* expressions to the query in a fluent API way).
*
* Currently only beans based on raw sql will use the having clause.
*
* This is similar to {@link #having()} except it returns the query rather
* than the ExpressionList. This is useful when you want to further specify
* something on the query.
*
* This follows SQL syntax using commas between each property with the
* optional asc and desc keywords representing ascending and descending order
* respectively.
*/
Query
* This follows SQL syntax using commas between each property with the
* optional asc and desc keywords representing ascending and descending order
* respectively.
*/
Query
* This will never return a null. If no order by clause exists then an 'empty'
* OrderBy object is returned.
*
* This is the same as
* This will never return a null. If no order by clause exists then an 'empty'
* OrderBy object is returned.
*
* This is the same as
* The select() clause MUST be specified when setDistinct(true) is set. The reason for this is that
* generally ORM queries include the "id" property and this doesn't make sense for distinct queries.
*
* If no property is set then the id property is used.
*
* This method is now superseded by {@link #setBeanCacheMode(CacheMode)}
* which provides more explicit options controlled bean cache use.
*
* This method is likely to be deprecated in the future with migration
* over to setUseBeanCache().
*
* By default "find by id" and "find by natural key" will use the bean cache
* when bean caching is enabled. Setting this to false means that the query
* will not use the bean cache and instead hit the database.
*
* By default findList() with natural keys will not use the bean cache. In that
* case we need to explicitly use the bean cache.
*
* This label can be used to help identify query performance metrics but we can also use
* profile location enhancement on Finders so for some that would be a better option.
*
* When setting this you may also consider disabling lazy loading.
*
* When set to true all the beans from this query are loaded into the bean cache.
*/
Query
* 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.
*
* Note that internally findEach and findEachWhile will set the fetch size
* if it has not already as these queries expect to process a lot of rows.
* If we didn't then Postgres and MySql for example would eagerly pull back
* all the row data and potentially consume a lot of memory in the process.
*
* As findEach and findEachWhile automatically set the fetch size we don't have
* to do so generally but we might still wish to for tuning a specific use case.
*
* This is only available after the query has been executed and provided only
* for informational purposes.
*
* Note that
* Provides us with the ability to explicitly use Postgres
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
*/
Query
* Note that
* Provides us with the ability to explicitly use Postgres
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
*/
Query
* The same as
* This is typically a Postgres and Oracle only option at this stage.
*
* The same as
* This is typically a Postgres and Oracle only option at this stage.
*
* The same as
* Typically this is used when a table has partitioning and we wish to specify a specific
* partition/table to query against.
*
* That is, once the object graph is returned further lazy loading is disabled.
*
* Validate the query checking the where and orderBy expression paths to confirm if
* they represent valid properties or paths for the given bean type.
* {@code
*
* int rowsUpdated = new QCustomer()
* .name.startsWith("Rob")
* .asUpdate()
* .set("active", false)
* .update();;
*
* }
*
* {@code
*
* int rowsUpdated = new QContact()
* .notes.note.startsWith("Make Inactive")
* .email.endsWith("@foo.com")
* .customer.id.equalTo(42)
* .asUpdate()
* .set("inactive", true)
* .setRaw("email = lower(email)")
* .update();
*
* }
*/
UpdateQuery{@code
*
* // explicitly specify the indexes to search
* query.setDocIndexName("logstash-2016.11.5,logstash-2016.11.6")
*
* // search today's index
* query.setDocIndexName("$today")
*
* // search the last 3 days
* query.setDocIndexName("$last-3")
*
* }
* {@code
*
* // search today's index
* query.setDocIndexName("$today")
*
* // search the last 3 days
* query.setDocIndexName("$last-3")
*
* }
*
* @param indexName The index or indexes to search against
* @return This query
*/
Query{@code
*
* // fetch a bean with JSON content
* EBasicJsonList bean= DB.find(EBasicJsonList.class)
* .setId(42)
* .setAllowLoadErrors() // collect errors into bean state if we have invalid JSON
* .findOne();
*
*
* // get the invalid JSON errors from the bean state
* Map
*/
Query{@code
*
* List
*
* @param fetchProperties the properties to fetch for this bean (* = all properties).
*/
Query{@code
*
* // query orders...
* List
* {@code
*
* // fetch customers (their id, name and status)
* List
*
* @param path the property path we wish to fetch eagerly.
* @param fetchProperties properties of the associated bean that you want to include in the
* fetch (* means all properties, null also means all properties).
*/
Query{@code
*
* fetch(path, fetchProperties, FetchConfig.ofQuery())
*
* }
* {@code
*
* fetch(path, fetchProperties, FetchConfig.ofLazy())
*
* }
*
*
*
* @param path the property path we wish to fetch lazily.
* @param fetchProperties properties of the associated bean that you want to include in the
* fetch (* means all properties, null also means all properties).
*/
Query{@code
*
* // fetch customers (their id, name and status)
* List
*
* @param path the property path we wish to fetch eagerly.
*/
Query{@code
*
* // fetch customers (their id, name and status)
* List
*
* @param path the property path we wish to fetch eagerly.
*/
Query{@code
*
* fetch(path, FetchConfig.ofQuery())
*
* }
* {@code
*
* fetch(path, FetchConfig.ofLazy())
*
* }
*
*
*
* @param path the property path we wish to fetch lazily.
*/
Query{@code
*
* // fetch customers (their id, name and status)
* List
*/
Query{@code
*
* Query
*/
@Nonnull
QueryIterator{@code
*
* // use try with resources to ensure Stream is closed
*
* try (Stream
*/
@Nonnull
Stream{@code
*
* // use try with resources to ensure Stream is closed
*
* try (Stream
*/
@Nonnull
@Deprecated
Stream{@code
*
* DB.find(Customer.class)
* .where().eq("status", Status.NEW)
* .order().asc("id")
* .findEach((Customer customer) -> {
*
* // do something with customer
* System.out.println("-- visit " + customer);
* });
*
* }
*
* @param consumer the consumer used to process the queried beans.
*/
void findEach(Consumer> consumer);
/**
* Execute the query using callbacks to a visitor to process the resulting
* beans one at a time.
*
{@code
*
* DB.find(Customer.class)
* .fetchQuery("contacts")
* .where().eq("status", Status.NEW)
* .order().asc("id")
* .setMaxRows(2000)
* .findEachWhile((Customer customer) -> {
*
* // do something with customer
* System.out.println("-- visit " + customer);
*
* // return true to continue processing or false to stop
* return (customer.getId() < 40);
* });
*
* }
*
* @param consumer the consumer used to process the queried beans.
*/
void findEachWhile(Predicate{@code
*
* List
*/
@Nonnull
List{@code
*
* Set
*/
@Nonnull
Set{@code
*
* Map
*/
@Nonnull
Example 1:
* {@code
*
* List
* Example 2:
* {@code
*
* List
*
* @return the list of values for the selected property
*/
@Nonnull
List findSingleAttributeList();
/**
* Execute a query returning a single value of a single property/column.
* {@code
*
* String name =
* DB.find(Customer.class)
* .select("name")
* .where().eq("id", 42)
* .findSingleAttribute();
*
* }
*/
A findSingleAttribute();
/**
* Return true if this is countDistinct query.
*/
boolean isCountDistinct();
/**
* Execute the query returning true if a row is found.
* Example using a query bean:
* {@code
*
* boolean userExists =
* new QContact()
* .email.equalTo("rob@foo.com")
* .exists();
*
* }
*
* Example:
* {@code
*
* boolean userExists = query()
* .where().eq("email", "rob@foo.com")
* .exists();
*
* }
*
* @return True if the query finds a matching row in the database
*/
boolean exists();
/**
* Execute the query returning either a single bean or null (if no matching
* bean is found).
* {@code
*
* // assuming the sku of products is unique...
* Product product = DB.find(Product.class)
* .where().eq("sku", "aa113")
* .findOne();
* ...
* }
* {@code
*
* // Fetch order 1 and additionally fetch join its order details...
* Order order = DB.find(Order.class)
* .setId(1)
* .fetch("details")
* .findOne();
*
* // the order details were eagerly loaded
* List
*
* @throws NonUniqueResultException if more than one result was found
*/
@Nullable
T findOne();
/**
* Execute the query returning an optional bean.
*/
@Nonnull
Optional{@code
*
* PagedList
*
* @return The PagedList
*/
@Nonnull
PagedList{@code
*
* // a query with a named parameter
* String oql = "find order where status = :orderStatus";
*
* List
*
* @param name the parameter name
* @param value the parameter value
*/
Query{@code
*
* // a query with a positioned parameter
* String oql = "where status = ? order by id desc";
*
* List
*
* @param position the parameter bind position starting from 1 (not 0)
* @param value the parameter bind value.
*/
Query{@code
*
* // a query with a positioned parameters
* String oql = "where status = ? and name = ?";
*
* List
*/
Query{@code
*
* Order order = DB.find(Order.class)
* .setId(1)
* .fetch("details")
* .findOne();
*
* // the order details were eagerly fetched
* List
*/
Query{@code
*
* List
*/
Query{@code
*
* List
*
* @return The ExpressionList for adding expressions to.
* @see Expr
*/
ExpressionList{@code
*
* List
* orderBy()
*/
OrderByorder()
*/
OrderBy{@code
*
* List
*/
Query{@code
*
* List
*/
Query{@code
*
* // Assuming sku is unique for products...
*
* Map
*
* @param mapKey the property to use as keys for a map.
*/
QueryON or OFF.
*/
default QueryforUpdate() is the same as
* withLock(LockType.UPDATE).
* forUpdateNoWait() is the same as
* withLock(LockType.UPDATE, LockWait.NOWAIT).
* withLock(LockType.UPDATE, LockWait.WAIT).
*/
QuerywithLock(LockType.UPDATE, LockWait.NOWAIT).
*/
QuerywithLock(LockType.UPDATE, LockWait.SKIPLOCKED).
*/
Query{@code
*
* QOrder()
* .setBaseTable("order_2019_05")
* .status.equalTo(Status.NEW)
* .findList();
*
* }
*/
Query{@code
*
* List
*
* @param type An inheritance subtype of the
*/
Query