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 * 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, 10); 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 < 1) { 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, 10); 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 * 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 * 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 * <p> 161 * This will load all beans on this path eagerly unless a {@link #lazy(int)} 162 * is also used. 163 * </p> 164 * 165 * @param batchSize the batch size used to load beans on this path 166 */ 167 @Deprecated 168 public FetchConfig query(int batchSize) { 169 return mutate(QUERY_MODE, batchSize); 170 } 171 172 /** 173 * Deprecated - migrate to FetchConfig.ofQuery(batchSize). 174 * 175 * Eagerly fetch the first batch of beans on this path. 176 * This is similar to {@link #query(int)} but only fetches the first batch. 177 * <p> 178 * If there are more parent beans than the batch size then they will not be 179 * loaded eagerly but instead use lazy loading. 180 * </p> 181 * 182 * @param batchSize the number of parent beans this path is populated for 183 */ 184 @Deprecated 185 public FetchConfig queryFirst(int batchSize) { 186 return query(batchSize); 187 } 188 189 /** 190 * Deprecated - migrate to FetchConfig.ofCache(). 191 * 192 * Eagerly fetch the beans fetching the beans from the L2 bean cache 193 * and using the DB for beans not in the cache. 194 */ 195 @Deprecated 196 public FetchConfig cache() { 197 return mutate(CACHE_MODE, 100); 198 } 199 200 /** 201 * Return the batch size for fetching. 202 */ 203 public int getBatchSize() { 204 return batchSize; 205 } 206 207 /** 208 * Return true if the fetch should use the L2 cache. 209 */ 210 public boolean isCache() { 211 return mode == CACHE_MODE; 212 } 213 214 /** 215 * Return true if the fetch should be a eager secondary query. 216 */ 217 public boolean isQuery() { 218 return mode == QUERY_MODE; 219 } 220 221 /** 222 * Return true if the fetch should be a lazy query. 223 */ 224 public boolean isLazy() { 225 return mode == LAZY_MODE; 226 } 227 228 /** 229 * Return true if the fetch should try to use SQL join. 230 */ 231 public boolean isJoin() { 232 return mode == JOIN_MODE; 233 } 234 235 @Override 236 public boolean equals(Object o) { 237 if (this == o) return true; 238 if (o == null || getClass() != o.getClass()) return false; 239 return (hashCode == ((FetchConfig) o).hashCode); 240 } 241 242 @Override 243 public int hashCode() { 244 return hashCode; 245 } 246}