#1271 - ENH: Add BeanFinder and BeanRepository ... such that there is a read to go base class for DI repository style

This commit is contained in:
Rob Bygrave
2018-02-23 16:55:07 +13:00
parent ff111eaf33
commit 7d0ed261b5
4 changed files with 444 additions and 0 deletions
+169
View File
@@ -0,0 +1,169 @@
package io.ebean;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Optional;
/**
* Provides finder functionality for use with "Dependency Injection style" use of Ebean.
* <p>
* Note that typically users would extend BeanRepository rather than BeanFinder.
* </p>
* <pre>{@code
*
* public class CustomerFinder extends BeanFinder<Long,Customer> {
*
* @Inject
* public CustomerFinder(EbeanServer server) {
* super(Customer.class, server);
* }
*
* // ... add customer specific finders
* }
*
* }</pre>
*
* @param <I> The ID type
* @param <T> The Bean type
*/
public abstract class BeanFinder<I,T> {
protected final EbeanServer server;
protected final Class<T> type;
/**
* Create with the given bean type and EbeanServer instance.
*
* @param type The bean type
* @param server The EbeanServer instance typically created via Spring factory or equivalent.
*/
protected BeanFinder(Class<T> type, EbeanServer server) {
this.type = type;
this.server = server;
}
/**
* Return the EbeanServer to use.
*/
public EbeanServer db() {
return server;
}
/**
* Return the current transaction.
*/
public Transaction currentTransaction() {
return db().currentTransaction();
}
/**
* Flush the JDBC batch on the current transaction.
*/
public void flush() {
db().flush();
}
/**
* Return typically a different EbeanServer to the default.
* <p>
* This is equivalent to {@link Ebean#getServer(String)}
*
* @param server The name of the EbeanServer. If this is null then the default EbeanServer is
* returned.
*/
public EbeanServer db(String server) {
return Ebean.getServer(server);
}
/**
* Creates an entity reference for this ID.
* <p>
* Equivalent to {@link EbeanServer#getReference(Class, Object)}
*/
@Nonnull
public T ref(I id) {
return db().getReference(type, id);
}
/**
* Retrieves an entity by ID.
* <p>
* Equivalent to {@link EbeanServer#find(Class, Object)}
*/
@Nullable
public T findById(I id) {
return db().find(type, id);
}
/**
* Find an entity by ID returning an Optional.
*/
@Nullable
public Optional<T> findByIdOrEmpty(I id) {
return db().find(type).setId(id).findOneOrEmpty();
}
/**
* Delete a bean by Id.
* <p>
* Equivalent to {@link EbeanServer#delete(Class, Object)}
*/
public void deleteById(I id) {
db().delete(type, id);
}
/**
* Retrieves all entities of the given type.
*/
@Nonnull
public List<T> findAll() {
return query().findList();
}
/**
* Creates an update query.
*
* <pre>{@code
*
* int rows =
* updateQuery()
* .set("status", Customer.Status.ACTIVE)
* .set("updtime", new Timestamp(System.currentTimeMillis()))
* .where()
* .gt("id", 1000)
* .update();
*
* }</pre>
*
* <p>
* Equivalent to {@link EbeanServer#update(Class)}
*/
protected UpdateQuery<T> updateQuery() {
return db().update(type);
}
/**
* Creates a query.
* <p>
* Equivalent to {@link EbeanServer#find(Class)}
*/
protected Query<T> query() {
return db().find(type);
}
/**
* Creates a native sql query.
*/
protected Query<T> nativeSql(String nativeSql) {
return db().findNative(type, nativeSql);
}
/**
* Creates a query using the ORM query language.
*/
protected Query<T> query(String ormQuery) {
return db().createQuery(type, ormQuery);
}
}
+178
View File
@@ -0,0 +1,178 @@
package io.ebean;
import io.ebean.bean.EntityBean;
/**
* Provides finder functionality for use with "Dependency Injection style" use of Ebean.
* <p>
* <pre>{@code
*
* @Repository
* public class CustomerRepository extends BeanRepository<Long,Customer> {
*
* @Inject
* public CustomerRepository(EbeanServer server) {
* super(Customer.class, server);
* }
*
* // ... add customer specific finders and persist logic
*
* public List<Customer> findByName(String nameStart) {
* return query().where()
* .istartsWith("name", nameStart)
* .findList();
* }
*
* }
* }</pre>
*
* @param <I> The ID type
* @param <T> The Bean type
*/
public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
/**
* Create with the given bean type and EbeanServer instance.
* <p>
* Typically users would extend BeanRepository rather than BeanFinder.
* </p>
* <pre>{@code
*
* @Inject
* public CustomerRepository(EbeanServer server) {
* super(Customer.class, server);
* }
*
* }</pre>
*
* @param type The bean type
* @param server The EbeanServer instance typically created via Spring factory or equivalent
*/
protected BeanRepository(Class<T> type, EbeanServer server) {
super(type, server);
}
/**
* Marks the entity bean as dirty.
* <p>
* This is used so that when a bean that is otherwise unmodified is updated the version
* property is updated.
* <p>
* An unmodified bean that is saved or updated is normally skipped and this marks the bean as
* dirty so that it is not skipped.
* <p>
* <pre>{@code
*
* Customer customer = customerRepository.byId(id);
*
* // mark the bean as dirty so that a save() or update() will
* // increment the version property
*
* customerRepository.markAsDirty(customer);
* customerRepository.save(customer);
*
* }</pre>
*
* @see EbeanServer#markAsDirty(Object)
*/
public void markAsDirty(T bean) {
db().markAsDirty(bean);
}
/**
* Mark the property as unset or 'not loaded'.
* <p>
* This would be used to specify a property that we did not wish to include in a stateless update.
* </p>
* <pre>{@code
*
* // populate an entity bean from JSON or whatever
* Customer customer = ...;
*
* // mark the email property as 'unset' so that it is not
* // included in a 'stateless update'
* customerRepository.markPropertyUnset(customer, "email");
*
* customerRepository.update(customer);
*
* }</pre>
*
* @param propertyName the name of the property on the bean to be marked as 'unset'
*/
public void markPropertyUnset(T bean, String propertyName) {
((EntityBean) bean)._ebean_getIntercept().setPropertyLoaded(propertyName, false);
}
/**
* Insert or update this entity depending on its state.
* <p>
* Ebean will detect if this is a new bean or a previously fetched bean and perform either an
* insert or an update based on that.
*
* @see EbeanServer#save(Object)
*/
public void save(T bean) {
db().save(bean);
}
/**
* Update this entity.
*
* @see EbeanServer#update(Object)
*/
public void update(T bean) {
db().update(bean);
}
/**
* Insert this entity.
*
* @see EbeanServer#insert(Object)
*/
public void insert(T bean) {
db().insert(bean);
}
/**
* Delete this bean.
* <p>
* This will return true if the bean was deleted successfully or JDBC batch is being used.
* </p>
* <p>
* If there is no current transaction one will be created and committed for
* you automatically.
* </p>
* <p>
* If the Bean does not have a version property (or loaded version property) and
* the bean does not exist then this returns false indicating that nothing was
* deleted. Note that, if JDBC batch mode is used then this always returns true.
* </p>
*
* @see EbeanServer#delete(Object)
*/
public boolean delete(T bean) {
return db().delete(bean);
}
/**
* Delete a bean permanently without soft delete.
* <p>
* This is used when the bean contains a <code>@SoftDelete</code> property and we
* want to perform a hard/permanent delete.
* </p>
*
* @see EbeanServer#deletePermanent(Object)
*/
public boolean deletePermanent(T bean) {
return db().deletePermanent(bean);
}
/**
* Refreshes this entity from the database.
*
* @see EbeanServer#refresh(Object)
*/
public void refresh(T bean) {
db().refresh(bean);
}
}