001package io.ebean; 002 003import java.io.Serializable; 004 005/** 006 * Defines how a relationship is fetched via either normal SQL join, 007 * a eager secondary query, via lazy loading or via eagerly hitting L2 cache. 008 * <p> 009 * <pre>{@code 010 * // Normal fetch join results in a single SQL query 011 * List<Order> list = DB.find(Order.class).fetch("details").findList(); 012 * 013 * }</pre> 014 * <p> 015 * Example: Using a "query join" instead of a "fetch join" we instead use 2 SQL queries 016 * </p> 017 * <p> 018 * <pre>{@code 019 * 020 * // This will use 2 SQL queries to build this object graph 021 * List<Order> list = 022 * DB.find(Order.class) 023 * .fetch("details", FetchConfig.ofQuery()) 024 * .findList(); 025 * 026 * // query 1) find order 027 * // query 2) find orderDetails where order.id in (?,?...) // first 100 order id's 028 * 029 * }</pre> 030 * 031 * @author mario 032 * @author rbygrave 033 */ 034public class FetchConfig implements Serializable { 035 036 private static final long serialVersionUID = 1L; 037 038 private static final int JOIN_MODE = 0; 039 private static final int QUERY_MODE = 1; 040 private static final int LAZY_MODE = 2; 041 private static final int CACHE_MODE = 3; 042 043 private int mode; 044 private int batchSize; 045 private int hashCode; 046 047 /** 048 * Deprecated - migrate to one of the static factory methods like {@link FetchConfig#ofQuery()} 049 * <p> 050 * Construct using default JOIN mode. 051 */ 052 @Deprecated 053 public FetchConfig() { 054 //this.mode = JOIN_MODE; 055 this.batchSize = 100; 056 this.hashCode = 1000; 057 } 058 059 private FetchConfig(int mode, int batchSize) { 060 this.mode = mode; 061 this.batchSize = batchSize; 062 this.hashCode = mode + 10 * batchSize; 063 } 064 065 /** 066 * Return FetchConfig to eagerly fetch the relationship using L2 cache. 067 * <p> 068 * Any cache misses will be loaded by secondary query to the database. 069 */ 070 public static FetchConfig ofCache() { 071 return new FetchConfig(CACHE_MODE, 100); 072 } 073 074 /** 075 * Return FetchConfig to eagerly fetch the relationship using a secondary query. 076 */ 077 public static FetchConfig ofQuery() { 078 return new FetchConfig(QUERY_MODE, 100); 079 } 080 081 /** 082 * Return FetchConfig to eagerly fetch the relationship using a secondary with a given batch size. 083 */ 084 public static FetchConfig ofQuery(int batchSize) { 085 return new FetchConfig(QUERY_MODE, batchSize); 086 } 087 088 /** 089 * Return FetchConfig to lazily load the relationship. 090 */ 091 public static FetchConfig ofLazy() { 092 return new FetchConfig(LAZY_MODE, 0); 093 } 094 095 /** 096 * Return FetchConfig to lazily load the relationship specifying the batch size. 097 */ 098 public static FetchConfig ofLazy(int batchSize) { 099 return new FetchConfig(LAZY_MODE, batchSize); 100 } 101 102 /** 103 * Return FetchConfig to fetch the relationship using SQL join. 104 */ 105 public static FetchConfig ofDefault() { 106 return new FetchConfig(JOIN_MODE, 100); 107 } 108 109 /** 110 * We want to migrate away from mutating FetchConfig to a fully immutable FetchConfig. 111 */ 112 private FetchConfig mutate(int mode, int batchSize) { 113 if (batchSize < 0) { 114 throw new IllegalArgumentException("batch size " + batchSize + " must be > 0"); 115 } 116 this.mode = mode; 117 this.batchSize = batchSize; 118 this.hashCode = mode + 10 * batchSize; 119 return this; 120 } 121 122 /** 123 * Deprecated - migrate to FetchConfig.ofLazy(). 124 */ 125 @Deprecated 126 public FetchConfig lazy() { 127 return mutate(LAZY_MODE, 0); 128 } 129 130 /** 131 * Deprecated - migrate to FetchConfig.ofLazy(batchSize). 132 */ 133 @Deprecated 134 public FetchConfig lazy(int batchSize) { 135 return mutate(LAZY_MODE, batchSize); 136 } 137 138 /** 139 * Deprecated - migrate to FetchConfig.ofQuery(). 140 * <p> 141 * Eagerly fetch the beans in this path as a separate query (rather than as 142 * part of the main query). 143 * <p> 144 * This will use the default batch size for separate query which is 100. 145 */ 146 @Deprecated 147 public FetchConfig query() { 148 return mutate(QUERY_MODE, 100); 149 } 150 151 /** 152 * Deprecated - migrate to FetchConfig.ofQuery(batchSize). 153 * <p> 154 * Eagerly fetch the beans in this path as a separate query (rather than as 155 * part of the main query). 156 * <p> 157 * The queryBatchSize is the number of parent id's that this separate query 158 * will load per batch. 159 * <p> 160 * This will load all beans on this path eagerly unless a {@link #lazy(int)} 161 * is also used. 162 * 163 * @param batchSize the batch size used to load beans on this path 164 */ 165 @Deprecated 166 public FetchConfig query(int batchSize) { 167 return mutate(QUERY_MODE, batchSize); 168 } 169 170 /** 171 * Deprecated - migrate to FetchConfig.ofQuery(batchSize). 172 * <p> 173 * Eagerly fetch the first batch of beans on this path. 174 * This is similar to {@link #query(int)} but only fetches the first batch. 175 * <p> 176 * If there are more parent beans than the batch size then they will not be 177 * loaded eagerly but instead use lazy loading. 178 * 179 * @param batchSize the number of parent beans this path is populated for 180 */ 181 @Deprecated 182 public FetchConfig queryFirst(int batchSize) { 183 return query(batchSize); 184 } 185 186 /** 187 * Deprecated - migrate to FetchConfig.ofCache(). 188 * <p> 189 * Eagerly fetch the beans fetching the beans from the L2 bean cache 190 * and using the DB for beans not in the cache. 191 */ 192 @Deprecated 193 public FetchConfig cache() { 194 return mutate(CACHE_MODE, 100); 195 } 196 197 /** 198 * Return the batch size for fetching. 199 */ 200 public int getBatchSize() { 201 return batchSize; 202 } 203 204 /** 205 * Return true if the fetch should use the L2 cache. 206 */ 207 public boolean isCache() { 208 return mode == CACHE_MODE; 209 } 210 211 /** 212 * Return true if the fetch should be a eager secondary query. 213 */ 214 public boolean isQuery() { 215 return mode == QUERY_MODE; 216 } 217 218 /** 219 * Return true if the fetch should be a lazy query. 220 */ 221 public boolean isLazy() { 222 return mode == LAZY_MODE; 223 } 224 225 /** 226 * Return true if the fetch should try to use SQL join. 227 */ 228 public boolean isJoin() { 229 return mode == JOIN_MODE; 230 } 231 232 @Override 233 public boolean equals(Object o) { 234 if (this == o) return true; 235 if (o == null || getClass() != o.getClass()) return false; 236 return (hashCode == ((FetchConfig) o).hashCode); 237 } 238 239 @Override 240 public int hashCode() { 241 return hashCode; 242 } 243}