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

com.avaje.ebean.FetchConfig Maven / Gradle / Ivy

package com.avaje.ebean;

import java.io.Serializable;

/**
 * Defines the configuration options for a "query fetch" or a
 * "lazy loading fetch". This gives you the ability to use multiple smaller
 * queries to populate an object graph as opposed to a single large query.
 * 

* The primary goal is to provide efficient ways of loading complex object * graphs avoiding SQL Cartesian product and issues around populating object * graphs that have multiple *ToMany relationships. *

*

* It also provides the ability to control the lazy loading queries (batch size, * selected properties and fetches) to avoid N+1 queries etc. *

* There can also be cases loading across a single OneToMany where 2 SQL queries * using Ebean FetchConfig.query() can be more efficient than one SQL query. * When the "One" side is wide (lots of columns) and the cardinality difference * is high (a lot of "Many" beans per "One" bean) then this can be more * efficient loaded as 2 SQL queries. *

* *
{@code
 * // Normal fetch join results in a single SQL query
 * List list = Ebean.find(Order.class).fetch("details").findList();
 * 
 * // Find Orders join details using a single SQL query
 * }
*

* Example: Using a "query join" instead of a "fetch join" we instead use 2 SQL * queries *

* *
{@code
 * // This will use 2 SQL queries to build this object graph
 * List list =
 *     Ebean.find(Order.class)
 *         .fetch("details", new FetchConfig().query())
 *         .findList();
 * 
 * // query 1) find order
 * // query 2) find orderDetails where order.id in (?,?...) // first 100 order id's
 * }
*

* Example: Using 2 "query joins" *

* *
{@code
 * // This will use 3 SQL queries to build this object graph
 * List list =
 *     Ebean.find(Order.class)
 *         .fetch("details", new FetchConfig().query())
 *         .fetch("customer", new FetchConfig().queryFirst(5))
 *         .findList();
 * 
 * // query 1) find order
 * // query 2) find orderDetails where order.id in (?,?...) // first 100 order id's
 * // query 3) find customer where id in (?,?,?,?,?) // first 5 customers
 * }
*

* Example: Using "query joins" and partial objects *

* *
{@code
 * // This will use 3 SQL queries to build this object graph
 * List list =
 *     Ebean.find(Order.class)
 *         .select("status, shipDate")
 *         .fetch("details", "quantity, price", new FetchConfig().query())
 *         .fetch("details.product", "sku, name")
 *         .fetch("customer", "name", new FetchConfig().queryFirst(5))
 *         .fetch("customer.contacts")
 *         .fetch("customer.shippingAddress")
 *         .findList();
 * 
 * // query 1) find order (status, shipDate)
 * // query 2) find orderDetail (quantity, price) fetch product (sku, name) where
 * // order.id in (?,? ...)
 * // query 3) find customer (name) fetch contacts (*) fetch shippingAddress (*)
 * // where id in (?,?,?,?,?)
 * 
 * // Note: the fetch of "details.product" is automatically included into the
 * // fetch of "details"
 * //
 * // Note: the fetch of "customer.contacts" and "customer.shippingAddress"
 * // are automatically included in the fetch of "customer"
 * }
*

* You can use query() and lazy together on a single join. The query is executed * immediately and the lazy defines the batch size to use for further lazy * loading (if lazy loading is invoked). *

* *
{@code
 * List list =
 *     Ebean.find(Order.class)
 *         .fetch("customer", new FetchConfig().query(10).lazy(5))
 *         .findList();
 * 
 * // query 1) find order
 * // query 2) find customer where id in (?,?,?,?,?,?,?,?,?,?) // first 10 customers
 * // .. then if lazy loading of customers is invoked
 * // .. use a batch size of 5 to load the customers
 * 
 * }
* *

* Example of controlling the lazy loading query: *

*

* This gives us the ability to optimise the lazy loading query for a given use * case. *

* *
{@code
 * List list = Ebean.find(Order.class)
 *   .fetch("customer","name", new FetchConfig().lazy(5))
 *   .fetch("customer.contacts","contactName, phone, email")
 *   .fetch("customer.shippingAddress")
 *   .where().eq("status",Order.Status.NEW)
 *   .findList();
 * 
 * // query 1) find order where status = Order.Status.NEW
 * //  
 * // .. if lazy loading of customers is invoked 
 * // .. use a batch size of 5 to load the customers 
 *  
 *       find  customer (name) 
 *       fetch customer.contacts (contactName, phone, email) 
 *       fetch customer.shippingAddress (*) 
 *       where id in (?,?,?,?,?)
 * 
 * }
* * @author mario * @author rbygrave */ public class FetchConfig implements Serializable { private static final long serialVersionUID = 1L; private int lazyBatchSize = -1; private int queryBatchSize = -1; private boolean queryAll; /** * Construct the fetch configuration object. */ public FetchConfig() { } /** * Specify that this path should be lazy loaded using the default batch load * size. */ public FetchConfig lazy() { this.lazyBatchSize = 0; this.queryAll = false; return this; } /** * Specify that this path should be lazy loaded with a specified batch size. * * @param lazyBatchSize * the batch size for lazy loading */ public FetchConfig lazy(int lazyBatchSize) { this.lazyBatchSize = lazyBatchSize; this.queryAll = false; return this; } /** * Eagerly fetch the beans in this path as a separate query (rather than as * part of the main query). *

* This will use the default batch size for separate query which is 100. *

*/ public FetchConfig query() { this.queryBatchSize = 0; this.queryAll = true; return this; } /** * Eagerly fetch the beans in this path as a separate query (rather than as * part of the main query). *

* The queryBatchSize is the number of parent id's that this separate query * will load per batch. *

*

* This will load all beans on this path eagerly unless a {@link #lazy(int)} * is also used. *

* * @param queryBatchSize * the batch size used to load beans on this path */ public FetchConfig query(int queryBatchSize) { this.queryBatchSize = queryBatchSize; // queryAll true as long as a lazy batch size has not already been set this.queryAll = (lazyBatchSize == -1); return this; } /** * Eagerly fetch the first batch of beans on this path. * This is similar to {@link #query(int)} but only fetches the first batch. *

* If there are more parent beans than the batch size then they will not be * loaded eagerly but instead use lazy loading. *

* * @param queryBatchSize * the number of parent beans this path is populated for */ public FetchConfig queryFirst(int queryBatchSize) { this.queryBatchSize = queryBatchSize; this.queryAll = false; return this; } /** * Return the batch size for lazy loading. */ public int getLazyBatchSize() { return lazyBatchSize; } /** * Return the batch size for separate query load. */ public int getQueryBatchSize() { return queryBatchSize; } /** * Return true if the query fetch should fetch 'all' rather than just the * 'first' batch. */ public boolean isQueryAll() { return queryAll; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; FetchConfig that = (FetchConfig) o; if (lazyBatchSize != that.lazyBatchSize) return false; if (queryBatchSize != that.queryBatchSize) return false; return queryAll == that.queryAll; } @Override public int hashCode() { int result = lazyBatchSize; result = 92821 * result + queryBatchSize; result = 92821 * result + (queryAll ? 1 : 0); return result; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy