001package com.avaje.ebean;
002
003import com.avaje.ebean.bean.EntityBean;
004import com.avaje.ebean.util.ClassUtil;
005import org.jetbrains.annotations.Nullable;
006
007import javax.persistence.MappedSuperclass;
008import java.util.List;
009import java.util.Map;
010import java.util.Set;
011import java.util.UUID;
012
013/**
014 * A MappedSuperclass base class that provides convenience methods for inserting, updating and
015 * deleting beans.
016 * 
017 * <p>
018 * By having your entity beans extend this it provides a 'Active Record' style programming model for
019 * Ebean users.
020 * 
021 * <p>
022 * Note that there is a avaje-ebeanorm-mocker project that enables you to use Mockito or similar
023 * tools to still mock out the underlying 'default EbeanServer' for testing purposes.
024 * 
025 * <p>
026 * You may choose not use this Model mapped superclass if you don't like the 'Active Record' style
027 * or if you believe it 'pollutes' your entity beans.
028 *
029 * <p>
030 * You can use Dependency Injection like Guice or Spring to construct and wire a EbeanServer instance
031 * and have that same instance used with this Model and Finder. The way that works is that when the
032 * DI container creates the EbeanServer instance it can be registered with the Ebean singleton. In this
033 * way the EbeanServer instance can be injected as per normal Guice / Spring dependency injection and
034 * that same instance also used to support the Model and Finder active record style.
035 *
036 * <p>
037 * If you choose to use the Model mapped superclass you will probably also chose to additionally add
038 * a {@link Find} as a public static field to complete the active record pattern and provide a
039 * relatively nice clean way to write queries.
040 *
041 * <h3>Typical common @MappedSuperclass</h3>
042 * <pre>{@code
043 *
044 *     // Typically there is a common base model that has some
045 *     // common properties like the ones below
046 *
047 *     @MappedSuperclass
048 *     public class BaseModel extends Model {
049 *
050 *       @Id Long id;
051 *
052 *       @Version Long version;
053 *
054 *       @CreatedTimestamp Timestamp whenCreated;
055 *
056 *       @UpdatedTimestamp Timestamp whenUpdated;
057 *
058 *       ...
059 *
060 * }</pre>
061 *
062 * <h3>Extend the Model</h3>
063 * <pre>{@code
064 *
065 *     // Extend the mappedSuperclass
066 *
067 *     @Entity @Table(name="oto_account")
068 *     public class Customer extends BaseModel {
069 *
070 *       // Add a static Find
071 *       // ... with Long being the type of our @Id property.
072 *       // ... Note the {} at the end as Find is an abstract class.
073 *
074 *       public static final Find<Long,Account> find = new Find<Long,Account>(){};
075 *
076 *       String name;
077 *       ...
078 *     }
079 *
080 * }</pre>
081 *
082 * <h3>Modal: save()</h3>
083 * <pre>{@code
084 *
085 *     // Active record style ... save(), delete() etc
086 *     Customer customer = new Customer();
087 *     customer.setName("AC234");
088 *
089 *     // save() method inherited from Model
090 *     customer.save();
091 *
092 * }</pre>
093 *
094 * <h3>Find byId</h3>
095 * <pre>{@code
096 *
097 *     // find byId
098 *     Customer customer = Customer.find.byId(42);
099 *
100 * }</pre>
101 *
102 * <h3>Find where</h3>
103 * <pre>{@code
104 *
105 *     // find where ...
106 *     List<Customer> customers =
107 *         Customer.find
108 *         .where().gt("startDate", lastMonth)
109 *         .findList();
110 *
111 * }</pre>
112 */
113@MappedSuperclass
114public abstract class Model {
115
116  /**
117   * Return the underlying 'default' EbeanServer.
118   * 
119   * <p>
120   * This provides full access to the API such as explicit transaction demarcation etc.
121   * 
122   * <p>
123   * Example:
124   * <pre>{@code
125   *
126   * Transaction transaction = Customer.db().beginTransaction();
127   * try {
128   * 
129   *   // turn off cascade persist for this transaction
130   *   transaction.setPersistCascade(false);
131   * 
132   *   // extra control over jdbc batching for this transaction
133   *   transaction.setBatchGetGeneratedKeys(false);
134   *   transaction.setBatchMode(true);
135   *   transaction.setBatchSize(20);
136   * 
137   *   Customer customer = new Customer();
138   *   customer.setName(&quot;Roberto&quot;);
139   *   customer.save();
140   * 
141   *   Customer otherCustomer = new Customer();
142   *   otherCustomer.setName("Franko");
143   *   otherCustomer.save();
144   * 
145   *   transaction.commit();
146   * 
147   * } finally {
148   *   transaction.end();
149   * }
150   * 
151   * }</pre>
152   */
153  public static EbeanServer db() {
154    return Ebean.getDefaultServer();
155  }
156
157  /**
158   * Return a named EbeanServer that is typically different to the default server.
159   * 
160   * <p>
161   * If you are using multiple databases then each database has a name and maps to a single
162   * EbeanServer. You can use this method to get an EbeanServer for another database.
163   * 
164   * @param server
165   *          The name of the EbeanServer. If this is null then the default EbeanServer is returned.
166   */
167  public static EbeanServer db(String server) {
168    return Ebean.getServer(server);
169  }
170
171  /**
172   * Marks the entity bean as dirty.
173   * <p>
174   * This is used so that when a bean that is otherwise unmodified is updated the version
175   * property is updated.
176   * <p>
177   * An unmodified bean that is saved or updated is normally skipped and this marks the bean as
178   * dirty so that it is not skipped.
179   * 
180   * <pre>{@code
181   * 
182   * Customer customer = Customer.find.byId(id);
183   * 
184   * // mark the bean as dirty so that a save() or update() will
185   * // increment the version property
186   * customer.markAsDirty();
187   * customer.save();
188   * 
189   * }</pre>
190   *
191   * @see EbeanServer#markAsDirty(Object)
192   */
193  public void markAsDirty() {
194    db().markAsDirty(this);
195  }
196
197  /**
198   * Mark the property as unset or 'not loaded'.
199   * <p>
200   *   This would be used to specify a property that we did not wish to include in a stateless update.
201   * </p>
202   * <pre>{@code
203   *
204   *   // populate an entity bean from JSON or whatever
205   *   User user = ...;
206   *
207   *   // mark the email property as 'unset' so that it is not
208   *   // included in a 'stateless update'
209   *   user.markPropertyUnset("email");
210   *
211   *   user.update();
212   *
213   * }</pre>
214   *
215   * @param propertyName the name of the property on the bean to be marked as 'unset'
216   */
217  public void markPropertyUnset(String propertyName) {
218    ((EntityBean)this)._ebean_getIntercept().setPropertyLoaded(propertyName, false);
219  }
220
221  /**
222   * Insert or update this entity depending on its state.
223   * 
224   * <p>
225   * Ebean will detect if this is a new bean or a previously fetched bean and perform either an
226   * insert or an update based on that.
227   *
228   * @see EbeanServer#save(Object)
229   */
230  public void save() {
231    db().save(this);
232  }
233
234  /**
235   * Update this entity.
236   *
237   * @see EbeanServer#update(Object)
238   */
239  public void update() {
240    db().update(this);
241  }
242
243  /**
244   * Insert this entity.
245   *
246   * @see EbeanServer#insert(Object)
247   */
248  public void insert() {
249    db().insert(this);
250  }
251
252  /**
253   * Delete this bean.
254   * <p>
255   * This will return true if the bean was deleted successfully or JDBC batch is being used.
256   * </p>
257   * <p>
258   * If there is no current transaction one will be created and committed for
259   * you automatically.
260   * </p>
261   * <p>
262   * If the Bean does not have a version property (or loaded version property) and
263   * the bean does not exist then this returns false indicating that nothing was
264   * deleted. Note that, if JDBC batch mode is used then this always returns true.
265   * </p>
266   *
267   * @see EbeanServer#delete(Object)
268   */
269  public boolean delete() {
270    return db().delete(this);
271  }
272
273  /**
274   * Perform an update using this entity against the specified server.
275   */
276  public void update(String server) {
277    db(server).update(this);
278  }
279
280  /**
281   * Perform an insert using this entity against the specified server.
282   */
283  public void insert(String server) {
284    db(server).insert(this);
285  }
286
287  /**
288   * Perform a delete using this entity against the specified server.
289   */
290  public boolean delete(String server) {
291    return db(server).delete(this);
292  }
293
294  /**
295   * Refreshes this entity from the database.
296   *
297   * @see EbeanServer#refresh(Object)
298   */
299  public void refresh() {
300    db().refresh(this);
301  }
302
303  /**
304   * A concrete implementation of Find.
305   * <p>
306   * It should be preferred to use {@link Find} instead of Finder as that can use reflection to determine the class
307   * literal type of the entity bean.
308   * </p>
309   * @param <I> type of the Id property
310   * @param <T> type of the entity bean
311   */
312  public static class Finder<I, T> extends Find<I, T> {
313
314    /**
315     * Create with the type of the entity bean.
316     *
317     * <pre>{@code
318     *
319     * @Entity
320     * public class Customer extends BaseModel {
321     *
322     *   public static final Finder<Long,Customer> find = new Finder<Long,Customer>(Customer.class);
323     *   ...
324     *
325     * }</pre>
326     *
327     * <p/>
328     * The preferred approach is to instead use <code>Find</code> as below. This approach is more DRY in that it does
329     * not require the class literal Customer.class to be passed into the constructor.
330     *
331     * <pre>{@code
332     *
333     * @Entity
334     * public class Customer extends BaseModel {
335     *
336     *   public static final Find<Long,Customer> find = new Find<Long,Customer>(){};
337     *   ...
338     *
339     * }</pre>
340     */
341    public Finder(Class<T> type) {
342      super(null, type);
343    }
344
345    /**
346     * Create with the type of the entity bean and specific server name.
347     */
348    public Finder(String serverName, Class<T> type) {
349      super(serverName, type);
350    }
351
352    /**
353     * Please migrate to use {@link Find} or constructor <code>Finder(Class)</code> that
354     * does not have the idType parameter.
355     * <p/>
356     * Create with the type of the ID property and entity bean and specific server name.
357     *
358     * @deprecated
359     */
360    public Finder(Class<I> idType, Class<T> type) {
361      super(null, type);
362    }
363
364    /**
365     * Please migrate to use the constructor <code>Finder(String, Class)</code> that
366     * does not have the idType parameter.
367     * <p/>
368     * Create with the type of the ID property and entity bean and specific server name.
369     *
370     * @deprecated
371     */
372    public Finder(String serverName, Class<I> idType, Class<T> type) {
373      super(serverName, type);
374    }
375  }
376
377  /**
378   * Helper object for performing queries.
379   * 
380   * <p>
381   * Typically a Find instance is defined as a public static field on an entity bean class to provide a
382   * nice way to write queries.
383   *
384   * <h3>Example use:</h3>
385   *
386   * <pre>{@code
387   *
388   * @Entity
389   * public class Customer extends BaseModel {
390   *
391   *   public static final Find<Long,Customer> find = new Find<Long,Customer>(){};
392   *
393   *   ...
394   *
395   * }</pre>
396   * <p/>
397   * This enables you to write code like:
398   * <pre>{@code
399   *
400   * Customer customer = Customer.find.byId(42L);
401   *
402   * List<Customer> customers =
403   *     Customer.find
404   *         .select("name, dateOfBirth")
405   *         .findList();
406   *
407   * }</pre>
408   *
409   * <h3>Kotlin</h3>
410   * In Kotlin you would typically create Find as a companion object.
411   * <pre>{@code
412   *
413   *   // kotlin
414   *   companion object : Model.Find<Long, Product>() {}
415   *
416   * }</pre>
417   * @param <I>
418   *          The Id type. This is most often a {@link Long} but is also often a {@link UUID} or
419   *          {@link String}.
420   *
421   * @param <T>
422   *          The entity bean type
423   */
424  public static abstract class Find<I, T> {
425
426    /**
427     * The entity bean type.
428     */
429    private final Class<T> type;
430
431    /**
432     * The name of the EbeanServer, null for the default server.
433     */
434    private final String serverName;
435
436    /**
437     * Creates a finder for entity of type <code>T</code> with ID of type <code>I</code>.
438     * <p/>
439     * Typically you create Find as a public static field on each entity bean as the example below.
440     *
441     * <p/>
442     * Note that Find is an abstract class and hence <code>{}</code> is required. This is done so
443     * that the type (class literal) of the entity bean can be derived from the generics parameter.
444     *
445     * <pre>{@code
446     *
447     * @Entity
448     * public class Customer extends BaseModel {
449     *
450     *   // Note the trailing {} as Find is an abstract class.
451     *   // We do this so that we can derive the type literal Customer.class
452     *   // via reflection
453     *   public static final Find<Long,Customer> find = new Find<Long,Customer>(){};
454     *   ...
455     *
456     * }</pre>
457     * <p/>
458     * This enables you to write code like:
459     * <pre>{@code
460     *
461     * Customer customer = Customer.find.byId(42L);
462     *
463     * List<Customer> customers =
464     *     Customer.find
465     *        .select("name, email, dateOfBirth")
466     *        .findList();
467     *
468     * }</pre>
469     *
470     * <h3>Kotlin</h3>
471     * In Kotlin you would typically create it as a companion object.
472     *
473     * <pre>{@code
474     *
475     *   // kotlin
476     *   companion object : Model.Find<Long, Product>() {}
477     *
478     * }</pre>
479     */
480    @SuppressWarnings("unchecked")
481    public Find() {
482      this.serverName = null;
483      this.type = (Class<T>)ClassUtil.getSecondArgumentType(getClass());
484    }
485
486    /**
487     * Construct passing the class literal type of the entity type.
488     */
489    protected Find(String serverName, Class<T> type) {
490      this.serverName = serverName;
491      this.type = type;
492    }
493
494    /**
495     * Return the underlying 'default' EbeanServer.
496     * 
497     * <p>
498     * This provides full access to the API such as explicit transaction demarcation etc.
499     * 
500     */
501    public EbeanServer db() {
502      return Ebean.getServer(serverName);
503    }
504
505    /**
506     * Return typically a different EbeanServer to the default.
507     * <p>
508     * This is equivilent to {@link Ebean#getServer(String)}
509     * 
510     * @param server
511     *          The name of the EbeanServer. If this is null then the default EbeanServer is
512     *          returned.
513     */
514    public EbeanServer db(String server) {
515      return Ebean.getServer(server);
516    }
517
518    /**
519     * Creates a Finder for the named EbeanServer.
520     *
521     * <p>
522     * Create and return a new Finder for a different server.
523     */
524    public Finder<I, T> on(String server) {
525      return new Finder<I, T>(server, type);
526    }
527
528    /**
529     * Delete a bean by Id.
530     * <p>
531     * Equivalent to {@link EbeanServer#delete(Class, Object)}
532     */
533    public void deleteById(I id) {
534      db().delete(type, id);
535    }
536
537    /**
538     * Retrieves all entities of the given type.
539     * 
540     * <p>
541     * This is the same as (synonym for) {@link #findList()}
542     */
543    public List<T> all() {
544      return findList();
545    }
546
547    /**
548     * Retrieves an entity by ID.
549     * 
550     * <p>
551     * Equivalent to {@link EbeanServer#find(Class, Object)}
552     */
553    @Nullable
554    public T byId(I id) {
555      return db().find(type, id);
556    }
557
558    /**
559     * Creates an entity reference for this ID.
560     * 
561     * <p>
562     * Equivalent to {@link EbeanServer#getReference(Class, Object)}
563     */
564    public T ref(I id) {
565      return db().getReference(type, id);
566    }
567
568    /**
569     * Creates a filter for sorting and filtering lists of entities locally without going back to
570     * the database.
571     * <p>
572     * Equivalent to {@link EbeanServer#filter(Class)}
573     */
574    public Filter<T> filter() {
575      return db().filter(type);
576    }
577
578    /**
579     * Creates a query.
580     * <p>
581     * Equivalent to {@link EbeanServer#find(Class)}
582     */
583    public Query<T> query() {
584      return db().find(type);
585    }
586
587    /**
588     * Creates a query applying the path properties to set the select and fetch clauses.
589     * <p>
590     * Equivalent to {@link Query#apply(FetchPath)}
591     */
592    public Query<T> apply(FetchPath fetchPath) {
593      return db().find(type).apply(fetchPath);
594    }
595
596    /**
597     * Returns the next identity value.
598     * 
599     * @see EbeanServer#nextId(Class)
600     */
601    @SuppressWarnings("unchecked")
602    public I nextId() {
603      return (I) db().nextId(type);
604    }
605
606    /**
607     * Executes a query and returns the results as a list of IDs.
608     * <p>
609     * Equivalent to {@link Query#findIds()}
610     */
611    public List<Object> findIds() {
612      return query().findIds();
613    }
614
615    /**
616     * Execute the query consuming each bean one at a time.
617     * <p>
618     * This is generally used to process large queries where unlike findList
619     * you do not want to hold all the results in memory at once but instead
620     * process them one at a time (requiring far less memory).
621     * </p>
622     * Equivalent to {@link Query#findEach(QueryEachConsumer)}
623     */
624    public void findEach(QueryEachConsumer<T> consumer) {
625      query().findEach(consumer);
626    }
627
628    /**
629     * Execute the query consuming each bean one at a time.
630     * <p>
631     * Equivalent to {@link Query#findEachWhile(QueryEachWhileConsumer)}
632     * <p>
633     * This is similar to #findEach except that you return boolean
634     * true to continue processing beans and return false to stop
635     * processing early.
636     * </p>
637     * <p>
638     * This is generally used to process large queries where unlike findList
639     * you do not want to hold all the results in memory at once but instead
640     * process them one at a time (requiring far less memory).
641     * </p>
642     * Equivalent to {@link Query#findEachWhile(QueryEachWhileConsumer)}
643     */
644    public void findEachWhile(QueryEachWhileConsumer<T> consumer) {
645      query().findEachWhile(consumer);
646    }
647
648    /**
649     * Retrieves all entities of the given type.
650     * <p>
651     * The same as {@link #all()}
652     * <p>
653     * Equivalent to {@link Query#findList()}
654     */
655    public List<T> findList() {
656      return query().findList();
657    }
658
659    /**
660     * Returns all the entities of the given type as a set.
661     * <p>
662     * Equivalent to {@link Query#findSet()}
663     */
664    public Set<T> findSet() {
665      return query().findSet();
666    }
667
668    /**
669     * Retrieves all entities of the given type as a map of objects.
670     * <p>
671     * Equivalent to {@link Query#findMap()}
672     */
673    public Map<?, T> findMap() {
674      return query().findMap();
675    }
676
677    /**
678     * Executes the query and returns the results as a map of the objects specifying the map key
679     * property.
680     * <p>
681     * Equivalent to {@link Query#findMap(String, Class)}
682     */
683    public <K> Map<K, T> findMap(String keyProperty, Class<K> keyType) {
684      return query().findMap(keyProperty, keyType);
685    }
686
687    /**
688     * Return a PagedList of all entities of the given type (use where() to specify predicates as
689     * needed).
690     * <p>
691     * Equivalent to {@link Query#findPagedList(int, int)}
692     */
693    public PagedList<T> findPagedList(int pageIndex, int pageSize) {
694      return query().findPagedList(pageIndex, pageSize);
695    }
696
697    /**
698     * Executes a find row count query in a background thread.
699     * <p>
700     * Equivalent to {@link Query#findFutureRowCount()}
701     */
702    public FutureRowCount<T> findFutureRowCount() {
703      return query().findFutureRowCount();
704    }
705
706    /**
707     * Returns the total number of entities for this type. *
708     * <p>
709     * Equivalent to {@link Query#findRowCount()}
710     */
711    public int findRowCount() {
712      return query().findRowCount();
713    }
714
715    /**
716     * Returns the <code>ExpressionFactory</code> used by this query.
717     */
718    public ExpressionFactory getExpressionFactory() {
719      return query().getExpressionFactory();
720    }
721
722    /**
723     * Explicitly sets a comma delimited list of the properties to fetch on the 'main' entity bean,
724     * to load a partial object.
725     * <p>
726     * Equivalent to {@link Query#select(String)}
727     */
728    public Query<T> select(String fetchProperties) {
729      return query().select(fetchProperties);
730    }
731
732    /**
733     * Specifies a path to load including all its properties.
734     * <p>
735     * Equivalent to {@link Query#fetch(String)}
736     */
737    public Query<T> fetch(String path) {
738      return query().fetch(path);
739    }
740
741    /**
742     * Additionally specifies a <code>FetchConfig</code> to specify a 'query join' and/or define the
743     * lazy loading query.
744     * <p>
745     * Equivalent to {@link Query#fetch(String, FetchConfig)}
746     */
747    public Query<T> fetch(String path, FetchConfig joinConfig) {
748      return query().fetch(path, joinConfig);
749    }
750
751    /**
752     * Specifies a path to fetch with a specific list properties to include, to load a partial
753     * object.
754     * <p>
755     * Equivalent to {@link Query#fetch(String, String)}
756     */
757    public Query<T> fetch(String path, String fetchProperties) {
758      return query().fetch(path, fetchProperties);
759    }
760
761    /**
762     * Additionally specifies a <code>FetchConfig</code> to use a separate query or lazy loading to
763     * load this path.
764     * <p>
765     * Equivalent to {@link Query#fetch(String, String, FetchConfig)}
766     */
767    public Query<T> fetch(String assocProperty, String fetchProperties, FetchConfig fetchConfig) {
768      return query().fetch(assocProperty, fetchProperties, fetchConfig);
769    }
770
771    /**
772     * Adds expressions to the <code>where</code> clause with the ability to chain on the
773     * <code>ExpressionList</code>.
774     * <p>
775     * Equivalent to {@link Query#where()}
776     */
777    public ExpressionList<T> where() {
778      return query().where();
779    }
780
781    /**
782     * Returns the <code>order by</code> clause so that you can append an ascending or descending
783     * property to the <code>order by</code> clause.
784     * <p>
785     * This is exactly the same as {@link #orderBy}.
786     * <p>
787     * Equivalent to {@link Query#order()}
788     */
789    public OrderBy<T> order() {
790      return query().order();
791    }
792
793    /**
794     * Sets the <code>order by</code> clause, replacing the existing <code>order by</code> clause if
795     * there is one.
796     * <p>
797     * This is exactly the same as {@link #orderBy(String)}.
798     */
799    public Query<T> order(String orderByClause) {
800      return query().order(orderByClause);
801    }
802
803    /**
804     * Returns the <code>order by</code> clause so that you can append an ascending or descending
805     * property to the <code>order by</code> clause.
806     * <p>
807     * This is exactly the same as {@link #order}.
808     * <p>
809     * Equivalent to {@link Query#orderBy()}
810     */
811    public OrderBy<T> orderBy() {
812      return query().orderBy();
813    }
814
815    /**
816     * Set the <code>order by</code> clause replacing the existing <code>order by</code> clause if
817     * there is one.
818     * <p>
819     * This is exactly the same as {@link #order(String)}.
820     */
821    public Query<T> orderBy(String orderByClause) {
822      return query().orderBy(orderByClause);
823    }
824
825    /**
826     * Sets the first row to return for this query.
827     * <p>
828     * Equivalent to {@link Query#setFirstRow(int)}
829     */
830    public Query<T> setFirstRow(int firstRow) {
831      return query().setFirstRow(firstRow);
832    }
833
834    /**
835     * Sets the maximum number of rows to return in the query.
836     * <p>
837     * Equivalent to {@link Query#setMaxRows(int)}
838     */
839    public Query<T> setMaxRows(int maxRows) {
840      return query().setMaxRows(maxRows);
841    }
842
843    /**
844     * Sets the ID value to query.
845     * 
846     * <p>
847     * Use this to perform a find byId query but with additional control over the query such as
848     * using select and fetch to control what parts of the object graph are returned.
849     * <p>
850     * Equivalent to {@link Query#setId(Object)}
851     */
852    public Query<T> setId(Object id) {
853      return query().setId(id);
854    }
855
856    /**
857     * Create and return a new query using the OQL.
858     * <p>
859     * Equivalent to {@link EbeanServer#createQuery(Class, String)}
860     */
861    public Query<T> setQuery(String oql) {
862      return db().createQuery(type, oql);
863    }
864
865    /**
866     * Create and return a new query based on the <code>RawSql</code>.
867     * <p>
868     * Equivalent to {@link Query#setRawSql(RawSql)}
869     */
870    public Query<T> setRawSql(RawSql rawSql) {
871      return query().setRawSql(rawSql);
872    }
873
874    /**
875     * Create a query with explicit 'AutoTune' use.
876     */
877    public Query<T> setAutoTune(boolean autoTune) {
878      return query().setAutoTune(autoTune);
879    }
880
881    /**
882     * Create a query with the select with "for update" specified.
883     * 
884     * <p>
885     * This will typically create row level database locks on the selected rows.
886     */
887    public Query<T> setForUpdate(boolean forUpdate) {
888      return query().setForUpdate(forUpdate);
889    }
890
891    /**
892     * Create a query specifying whether the returned beans will be read-only.
893     */
894    public Query<T> setReadOnly(boolean readOnly) {
895      return query().setReadOnly(readOnly);
896    }
897
898    /**
899     * Create a query specifying if the beans should be loaded into the L2 cache.
900     */
901    public Query<T> setLoadBeanCache(boolean loadBeanCache) {
902      return query().setLoadBeanCache(loadBeanCache);
903    }
904
905    /**
906     * Create a query specifying if the L2 bean cache should be used.
907     */
908    public Query<T> setUseCache(boolean useBeanCache) {
909      return query().setUseCache(useBeanCache);
910    }
911
912    /**
913     * Create a query specifying if the L2 query cache should be used.
914     */
915    public Query<T> setUseQueryCache(boolean useQueryCache) {
916      return query().setUseQueryCache(useQueryCache);
917    }
918
919  }
920}