mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
#464 - ENH: Add draftRestore(Class<?> beanType, Object id) ... to refresh a draft from the live (@Draftable feature)
This commit is contained in:
@@ -1869,4 +1869,56 @@ public interface EbeanServer {
|
||||
*/
|
||||
<T> List<T> publish(Query<T> query);
|
||||
|
||||
/**
|
||||
* Restore the draft bean back to the live state.
|
||||
* <p>
|
||||
* The values from the live beans are set back to the draft bean and the
|
||||
* <code>@DraftDirty</code> and <code>@DraftReset</code> properties are reset.
|
||||
* </p>
|
||||
*
|
||||
* @param <T> the type of the entity bean
|
||||
* @param beanType the type of the entity bean
|
||||
* @param id the id of the entity bean to restore
|
||||
* @param transaction the transaction the restore process should use (can be null)
|
||||
*/
|
||||
<T> T draftRestore(Class<T> beanType, Object id, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Restore the draft bean back to the live state.
|
||||
* <p>
|
||||
* The values from the live beans are set back to the draft bean and the
|
||||
* <code>@DraftDirty</code> and <code>@DraftReset</code> properties are reset.
|
||||
* </p>
|
||||
*
|
||||
* @param <T> the type of the entity bean
|
||||
* @param beanType the type of the entity bean
|
||||
* @param id the id of the entity bean to restore
|
||||
*/
|
||||
<T> T draftRestore(Class<T> beanType, Object id);
|
||||
|
||||
/**
|
||||
* Restore the draft beans matching the query back to the live state.
|
||||
* <p>
|
||||
* The values from the live beans are set back to the draft bean and the
|
||||
* <code>@DraftDirty</code> and <code>@DraftReset</code> properties are reset.
|
||||
* </p>
|
||||
*
|
||||
* @param <T> the type of the entity bean
|
||||
* @param query the query used to select the draft beans to restore
|
||||
* @param transaction the transaction the restore process should use (can be null)
|
||||
*/
|
||||
<T> List<T> draftRestore(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Restore the draft beans matching the query back to the live state.
|
||||
* <p>
|
||||
* The values from the live beans are set back to the draft bean and the
|
||||
* <code>@DraftDirty</code> and <code>@DraftReset</code> properties are reset.
|
||||
* </p>
|
||||
*
|
||||
* @param <T> the type of the entity bean
|
||||
* @param query the query used to select the draft beans to restore
|
||||
*/
|
||||
<T> List<T> draftRestore(Query<T> query);
|
||||
|
||||
}
|
||||
|
||||
@@ -1659,6 +1659,41 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
return (liveBeans.size() == 1) ? liveBeans.get(0) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> draftRestore(Query<T> query, Transaction transaction) {
|
||||
|
||||
TransWrapper wrap = initTransIfRequired(transaction);
|
||||
try {
|
||||
SpiTransaction trans = wrap.transaction;
|
||||
List<T> beans = persister.draftRestore(query, trans);
|
||||
wrap.commitIfCreated();
|
||||
|
||||
return beans;
|
||||
|
||||
} catch (RuntimeException e) {
|
||||
wrap.rollbackIfCreated();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T draftRestore(Class<T> beanType, Object id, Transaction transaction) {
|
||||
|
||||
Query<T> query = find(beanType).setId(id);
|
||||
List<T> beans = draftRestore(query, transaction);
|
||||
return (beans.size() == 1) ? beans.get(0) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T draftRestore(Class<T> beanType, Object id) {
|
||||
return draftRestore(beanType, id, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> draftRestore(Query<T> query) {
|
||||
return draftRestore(query, null);
|
||||
}
|
||||
|
||||
private EntityBean checkEntityBean(Object bean) {
|
||||
if (bean == null) {
|
||||
throw new IllegalArgumentException(Message.msg("bean.isnull"));
|
||||
|
||||
@@ -93,4 +93,9 @@ public interface Persister {
|
||||
*/
|
||||
<T> List<T> publish(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Restore the draft beans back to the matching live beans.
|
||||
*/
|
||||
<T> List<T> draftRestore(Query<T> query, Transaction transaction);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.OrderBy;
|
||||
import com.avaje.ebean.PersistenceContextScope;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.SqlUpdate;
|
||||
import com.avaje.ebean.Transaction;
|
||||
@@ -1953,6 +1954,8 @@ public class BeanDescriptor<T> implements MetaBeanInfo, SpiBeanType<T> {
|
||||
* Optimise the draft query fetching any draftable element relationships.
|
||||
*/
|
||||
public void draftQueryOptimise(Query<T> query) {
|
||||
// use per query PersistenceContext to ensure fresh beans loaded
|
||||
query.setPersistenceContextScope(PersistenceContextScope.QUERY);
|
||||
draftHelp.draftQueryOptimise(query);
|
||||
}
|
||||
|
||||
|
||||
@@ -127,49 +127,82 @@ public final class DefaultPersister implements Persister {
|
||||
return executeOrQueue(new PersistRequestUpdateSql(server, updSql, (SpiTransaction) t, persistExecute));
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore draft beans to match live beans given the query.
|
||||
*/
|
||||
@Override
|
||||
public <T> List<T> publish(Query<T> query, Transaction transaction) {
|
||||
|
||||
query.asDraft();
|
||||
public <T> List<T> draftRestore(Query<T> query, Transaction transaction) {
|
||||
|
||||
Class<T> beanType = query.getBeanType();
|
||||
BeanDescriptor<T> desc = server.getBeanDescriptor(beanType);
|
||||
desc.draftQueryOptimise(query);
|
||||
|
||||
List<T> draftBeans = server.findList(query, transaction);
|
||||
DraftHandler<T> draftHandler = new DraftHandler<T>(desc, transaction);
|
||||
|
||||
List<T> liveBeans = draftHandler.fetchSourceBeans(query, false);
|
||||
PUB.debug("draftRestore [{}] count[{}]", desc.getName(), liveBeans.size());
|
||||
if (liveBeans.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
draftHandler.fetchDestinationBeans(liveBeans, true);
|
||||
|
||||
BeanManager<T> mgr = beanDescriptorManager.getBeanManager(beanType);
|
||||
|
||||
for (T liveBean: liveBeans) {
|
||||
T draftBean = draftHandler.publishToDestinationBean(liveBean);
|
||||
// reset @DraftDirty and @DraftReset properties
|
||||
draftHandler.resetDraft(draftBean);
|
||||
|
||||
PUB.trace("draftRestore bean [{}] id[{}]", desc.getName(), draftHandler.getId());
|
||||
update(createRequest(draftBean, transaction, null, mgr, Type.UPDATE, true, false));
|
||||
}
|
||||
|
||||
PUB.debug("draftRestore - complete for [{}]", desc.getName());
|
||||
return draftHandler.getDrafts();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to return the list of Id values for the list of beans.
|
||||
*/
|
||||
private <T> List<Object> getBeanIds(BeanDescriptor<T> desc, List<T> beans) {
|
||||
List<Object> idList = new ArrayList<Object>();
|
||||
for (T liveBean: beans) {
|
||||
idList.add(desc.getBeanId(liveBean));
|
||||
}
|
||||
return idList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish from draft to live given the query.
|
||||
*/
|
||||
@Override
|
||||
public <T> List<T> publish(Query<T> query, Transaction transaction) {
|
||||
|
||||
Class<T> beanType = query.getBeanType();
|
||||
BeanDescriptor<T> desc = server.getBeanDescriptor(beanType);
|
||||
|
||||
DraftHandler<T> draftHandler = new DraftHandler<T>(desc, transaction);
|
||||
|
||||
List<T> draftBeans = draftHandler.fetchSourceBeans(query, true);
|
||||
PUB.debug("publish [{}] count[{}]", desc.getName(), draftBeans.size());
|
||||
|
||||
if (draftBeans.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// get the list of Id's
|
||||
List<Object> idList = new ArrayList<Object>();
|
||||
for (T draftBean: draftBeans) {
|
||||
idList.add(desc.getBeanId(draftBean));
|
||||
}
|
||||
|
||||
// fetch existing live beans to update (or insert if missing)
|
||||
Query<T> liveBeansQuery = server.find(beanType).where().idIn(idList).query();
|
||||
desc.draftQueryOptimise(liveBeansQuery);
|
||||
|
||||
Map<?, T> liveBeans = liveBeansQuery.findMap();
|
||||
|
||||
List<T> livePublish = new ArrayList<T>(idList.size());
|
||||
draftHandler.fetchDestinationBeans(draftBeans, false);
|
||||
|
||||
BeanManager<T> mgr = beanDescriptorManager.getBeanManager(beanType);
|
||||
|
||||
DraftHandler draftHandler = new DraftHandler(desc);
|
||||
|
||||
List<T> livePublish = new ArrayList<T>(draftBeans.size());
|
||||
for (T draftBean: draftBeans) {
|
||||
Object draftID = desc.getBeanId(draftBean);
|
||||
T existingLiveBean = liveBeans.get(draftID);
|
||||
|
||||
T liveBean = desc.publish(draftBean, existingLiveBean);
|
||||
T liveBean = draftHandler.publishToDestinationBean(draftBean);
|
||||
livePublish.add(liveBean);
|
||||
|
||||
// reset @DraftDirty and @DraftReset properties
|
||||
draftHandler.resetDraft(draftBean);
|
||||
|
||||
Type persistType = (existingLiveBean == null) ? Type.INSERT : Type.UPDATE;
|
||||
PUB.trace("publish bean [{}] id[{}] type[{}]", desc.getName(), draftID, persistType);
|
||||
Type persistType = draftHandler.isInsert() ? Type.INSERT : Type.UPDATE;
|
||||
PUB.trace("publish bean [{}] id[{}] type[{}]", desc.getName(), draftHandler.getId(), persistType);
|
||||
|
||||
PersistRequestBean<T> request = createRequest(liveBean, transaction, null, mgr, persistType, true, true);
|
||||
if (persistType == Type.INSERT) {
|
||||
@@ -177,8 +210,6 @@ public final class DefaultPersister implements Persister {
|
||||
} else {
|
||||
update(request);
|
||||
}
|
||||
|
||||
draftHandler.resetDraft(draftBean);
|
||||
}
|
||||
|
||||
draftHandler.updateDrafts(transaction, mgr);
|
||||
@@ -193,14 +224,38 @@ public final class DefaultPersister implements Persister {
|
||||
class DraftHandler<T> {
|
||||
|
||||
final BeanDescriptor<T> desc;
|
||||
final Transaction transaction;
|
||||
final BeanProperty draftDirty;
|
||||
final List<T> draftUpdates = new ArrayList<T>();
|
||||
|
||||
DraftHandler(BeanDescriptor<T> desc) {
|
||||
/**
|
||||
* Id value of the last published bean.
|
||||
*/
|
||||
Object id;
|
||||
|
||||
/**
|
||||
* True if the last published bean is new/insert.
|
||||
*/
|
||||
boolean insert;
|
||||
|
||||
/**
|
||||
* The destination beans to publish/restore to mapped by id.
|
||||
*/
|
||||
Map<?, T> destBeans;
|
||||
|
||||
DraftHandler(BeanDescriptor<T> desc, Transaction transaction) {
|
||||
this.desc = desc;
|
||||
this.transaction = transaction;
|
||||
this.draftDirty = desc.getDraftDirty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of draft beans with changes (to be persisted).
|
||||
*/
|
||||
List<T> getDrafts() {
|
||||
return draftUpdates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the draft dirty state to false and reset any dirtyReset properties.
|
||||
*/
|
||||
@@ -224,6 +279,56 @@ public final class DefaultPersister implements Persister {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the source beans based on the query.
|
||||
*/
|
||||
List<T> fetchSourceBeans(Query<T> query, boolean asDraft) {
|
||||
desc.draftQueryOptimise(query);
|
||||
if (asDraft) {
|
||||
query.asDraft();
|
||||
}
|
||||
return server.findList(query, transaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the destination beans that will be published to.
|
||||
*/
|
||||
void fetchDestinationBeans(List<T> sourceBeans, boolean asDraft) {
|
||||
|
||||
List<Object> ids = getBeanIds(desc, sourceBeans);
|
||||
|
||||
Query<T> destQuery = server.find(desc.getBeanType()).where().idIn(ids).query();
|
||||
if (asDraft) {
|
||||
destQuery.asDraft();
|
||||
}
|
||||
desc.draftQueryOptimise(destQuery);
|
||||
this.destBeans = server.findMap(destQuery, transaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish/restore the values from the sourceBean to the matching destination bean.
|
||||
*/
|
||||
T publishToDestinationBean(T sourceBean) {
|
||||
id = desc.getBeanId(sourceBean);
|
||||
T destBean = destBeans.get(id);
|
||||
insert = (destBean == null);
|
||||
// apply changes from liveBean to draftBean
|
||||
return desc.publish(sourceBean, destBean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the last publish resulted in an new bean to insert.
|
||||
*/
|
||||
boolean isInsert() {
|
||||
return insert;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Id value of the last published/restored bean.
|
||||
*/
|
||||
Object getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -367,6 +367,26 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T draftRestore(Class<T> beanType, Object id, Transaction transaction) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> draftRestore(Query<T> query, Transaction transaction) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T draftRestore(Class<T> beanType, Object id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> draftRestore(Query<T> query) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transaction createTransaction() {
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user