mirror of
https://github.com/ebean-orm/ebean.git
synced 2026-10-24 23:56:36 +00:00
#483 - ENH: Draftable - Add FK from live table back to draft table (for top level @Draftable tables)
This commit is contained in:
@@ -10,6 +10,7 @@ import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The context used during DDL generation.
|
||||
@@ -134,11 +135,22 @@ public class ModelBuildContext {
|
||||
/**
|
||||
* Create the draft table for a given table.
|
||||
*/
|
||||
public void createDraft(MTable table) {
|
||||
public void createDraft(MTable table, boolean draftable) {
|
||||
|
||||
MTable draftTable = table.createDraftTable();
|
||||
draftTable.setPkName(primaryKeyName(draftTable.getName()));
|
||||
|
||||
if (draftable) {
|
||||
// Add a FK from @Draftable live table back to it's draft table)
|
||||
List<MColumn> pkCols = table.primaryKeyColumns();
|
||||
if (pkCols.size() == 1) {
|
||||
// only doing this for single column PK at this stage
|
||||
MColumn pk = pkCols.get(0);
|
||||
pk.setReferences(draftTable.getName() + "." + pk.getName());
|
||||
pk.setForeignKeyName(foreignKeyConstraintName(table.getName(), pk.getName(), 0));
|
||||
}
|
||||
}
|
||||
|
||||
int fkCount = 0;
|
||||
int ixCount = 0;
|
||||
int uqCount = 0;
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ public class ModelBuildIntersectionTable {
|
||||
buildFkConstraints();
|
||||
|
||||
if (manyProp.getTargetDescriptor().isDraftable()) {
|
||||
ctx.createDraft(intersectionTable);
|
||||
ctx.createDraft(intersectionTable, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -112,7 +112,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
||||
private void addDraftTable() {
|
||||
if (beanDescriptor.isDraftable() || beanDescriptor.isDraftableElement()) {
|
||||
// create a 'Draft' table which looks very similar (change PK, FK etc)
|
||||
ctx.createDraft(table);
|
||||
ctx.createDraft(table, !beanDescriptor.isDraftableElement());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -151,12 +151,29 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
}
|
||||
this.concurrencyMode = beanDescriptor.getConcurrencyMode(intercept);
|
||||
this.publish = publish;
|
||||
if (!publish && beanDescriptor.isDraftable()) {
|
||||
if (isMarkDraftDirty(publish)) {
|
||||
beanDescriptor.setDraftDirty(entityBean, true);
|
||||
}
|
||||
this.dirty = intercept.isDirty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the draftDirty property should be set to true for this request.
|
||||
*/
|
||||
private boolean isMarkDraftDirty(boolean publish) {
|
||||
return !publish && type != Type.DELETE && beanDescriptor.isDraftable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the transaction from prior persist request.
|
||||
* Only used when hard deleting draft & associated live beans.
|
||||
*/
|
||||
public void setTrans(SpiTransaction transaction) {
|
||||
this.transaction = transaction;
|
||||
this.createdTransaction = false;
|
||||
this.persistCascade = transaction.isPersistCascade();
|
||||
}
|
||||
|
||||
/**
|
||||
* Init the transaction and also check for batch on cascade escalation.
|
||||
*/
|
||||
@@ -437,6 +454,21 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
return beanDescriptor.isDraftable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this request is a hard delete of a draftable bean.
|
||||
* If this is true Ebean is expected to auto-publish and delete the associated live bean.
|
||||
*/
|
||||
public boolean isHardDeleteDraft() {
|
||||
if (type == Type.DELETE && beanDescriptor.isDraftable() && !beanDescriptor.isDraftableElement()) {
|
||||
// deleting a top level draftable bean
|
||||
if (!beanDescriptor.isDraftInstance(entityBean)) {
|
||||
throw new PersistenceException("Explicit Delete is not allowed on a 'live' bean - only draft beans");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for @Draftable entity beans with @Draft property that the bean is a 'draft'.
|
||||
* Save or Update is not allowed to execute using 'live' beans - must use publish().
|
||||
|
||||
@@ -502,21 +502,31 @@ public final class DefaultPersister implements Persister {
|
||||
public boolean delete(EntityBean bean, Transaction t, boolean permanent) {
|
||||
|
||||
Type deleteType = permanent ? Type.DELETE_PERMANENT : Type.DELETE;
|
||||
PersistRequestBean<EntityBean> request = createRequest(bean, t, deleteType);
|
||||
boolean deleted = deleteRequest(request);
|
||||
PersistRequestBean<EntityBean> originalRequest = createRequest(bean, t, deleteType);
|
||||
|
||||
if (request.isDraftable() && request.getType() == Type.DELETE) {
|
||||
// we have just deleting a draft bean so now we need to delete the
|
||||
// associated 'live' bean. This is effectively an 'automatic publish'.
|
||||
deleteRequest(createPublishRequest(request.createReference(), t, Type.DELETE_PERMANENT, true));
|
||||
if (originalRequest.isHardDeleteDraft()) {
|
||||
// a hard delete of a draftable bean so first we need to delete the associated 'live' bean
|
||||
// due to FK constraint and then after that execute the original delete of the draft bean
|
||||
return deleteRequest(createPublishRequest(originalRequest.createReference(), t, Type.DELETE_PERMANENT, true), originalRequest);
|
||||
|
||||
} else {
|
||||
// normal delete or soft delete
|
||||
return deleteRequest(originalRequest);
|
||||
}
|
||||
return deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the delete request returning true if a delete occurred.
|
||||
*/
|
||||
private boolean deleteRequest(PersistRequestBean<?> req) {
|
||||
return deleteRequest(req, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the delete request support a second delete request for live and draft permanent delete.
|
||||
* A common transaction is used across both requests.
|
||||
*/
|
||||
private boolean deleteRequest(PersistRequestBean<?> req, PersistRequestBean<?> draftReq) {
|
||||
|
||||
if (req.isRegisteredForDeleteBean()) {
|
||||
// skip deleting bean. Used where cascade is on
|
||||
@@ -530,6 +540,11 @@ public final class DefaultPersister implements Persister {
|
||||
try {
|
||||
req.initTransIfRequiredWithBatchCascade();
|
||||
boolean deleted = delete(req);
|
||||
if (draftReq != null) {
|
||||
// delete the 'draft' bean ('live' bean deleted first)
|
||||
draftReq.setTrans(req.getTransaction());
|
||||
deleted = delete(draftReq);
|
||||
}
|
||||
req.commitTransIfRequired();
|
||||
req.flushBatchOnCascade();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user