From e0c3a92b6067ab52930e31fd420db2c8c573ffe4 Mon Sep 17 00:00:00 2001
From: rob bygrave
- * 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.
- *
*
* Example: Using a "query join" instead of a "fetch join" we instead use 2 SQL queries
@@ -37,103 +20,13 @@ import java.io.Serializable;
* // This will use 2 SQL queries to build this object graph
* List
- * Example: Using 2 "query joins"
- *
- *
- * Example: Using "query joins" and partial objects
- *
- *
- *
- * 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).
- *
- *
- *
- * Example of controlling the lazy loading query:
- *
- * This gives us the ability to optimise the lazy loading query for a given use
- * case.
- *
- *
+ * Any cache misses will be loaded by secondary query to the database.
+ */
+ public static FetchConfig ofCache() {
+ return new FetchConfig(CACHE_MODE, 100);
+ }
+
+ /**
+ * Return FetchConfig that use a eager secondary query to fetch the relationship.
+ */
+ public static FetchConfig ofQuery() {
+ return new FetchConfig(QUERY_MODE, 100);
+ }
+
+ /**
+ * Return FetchConfig that use a eager secondary query to fetch the relationship specifying the batch size.
+ */
+ public static FetchConfig ofQuery(int batchSize) {
+ return new FetchConfig(QUERY_MODE, batchSize);
+ }
+
+ /**
+ * Return FetchConfig that use lazy loading to fetch the relationship.
+ */
+ public static FetchConfig ofLazy() {
+ return new FetchConfig(LAZY_MODE, 10);
+ }
+
+ /**
+ * Return FetchConfig that use lazy loading to fetch the relationship specifying the batch size.
+ */
+ public static FetchConfig ofLazy(int batchSize) {
+ return new FetchConfig(LAZY_MODE, batchSize);
+ }
+
+ /**
+ * We want to migrate away from mutating FetchConfig to a fully immutable FetchConfig.
+ */
+ private FetchConfig mutate(int mode, int batchSize) {
+ if (batchSize < 1) {
+ throw new IllegalArgumentException("batch size "+batchSize+" must be > 0");
+ }
+ this.mode = mode;
+ this.batchSize = batchSize;
+ this.hashCode = mode + 10 * batchSize;
+ return this;
+ }
+
+ /**
+ * 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;
+ return mutate(LAZY_MODE, 10);
}
/**
* Specify that this path should be lazy loaded with a specified batch size.
*
- * @param lazyBatchSize the batch size for lazy loading
+ * @param batchSize the batch size for lazy loading
*/
- public FetchConfig lazy(int lazyBatchSize) {
- this.lazyBatchSize = lazyBatchSize;
- this.queryAll = false;
- return this;
+ public FetchConfig lazy(int batchSize) {
+ return mutate(LAZY_MODE, batchSize);
}
/**
- * Eagerly fetch the beans in this path as a separate query (rather than as
+ * Eagerly fetccd h 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.
* {@code
* // Normal fetch join results in a single SQL query
* List
* {@code
- *
- * // This will use 3 SQL queries to build this object graph
- * List
- * {@code
- * // This will use 3 SQL queries to build this object graph
- * List
- * {@code
- *
- * List
- * {@code
- *
- * List
*
* @author mario
* @author rbygrave
@@ -142,52 +35,105 @@ public class FetchConfig implements Serializable {
private static final long serialVersionUID = 1L;
- private int lazyBatchSize = -1;
+ private static final int JOIN_MODE = 0;
+ private static final int QUERY_MODE = 1;
+ private static final int LAZY_MODE = 2;
+ private static final int CACHE_MODE = 3;
- private int queryBatchSize = -1;
-
- private boolean queryAll;
-
- private boolean cache;
+ private int mode;
+ private int batchSize;
+ private int hashCode;
/**
- * Construct the fetch configuration object.
+ * Construct using default JOIN mode.
*/
public FetchConfig() {
+ //this.mode = JOIN_MODE;
+ this.batchSize = 100;
+ this.hashCode = 1000;
+ }
+
+ private FetchConfig(int mode, int batchSize) {
+ this.mode = mode;
+ this.batchSize = batchSize;
+ this.hashCode = mode + 10 * batchSize;
}
/**
- * Specify that this path should be lazy loaded using the default batch load
- * size.
+ * Return FetchConfig that will eagerly fetch the relationship using L2 cache.
+ *