mirror of
https://github.com/ebean-orm/ebean.git
synced 2026-10-20 16:40:35 +00:00
Co-authored-by: robin.bygrave <robin.bygrave@eroad.com>
This commit is contained in:
co-authored by
robin.bygrave
parent
1d654e350b
commit
a2f954a60e
@@ -132,6 +132,13 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
* Cascade to children must be suppressed to avoid FK violations.
|
||||
*/
|
||||
private boolean insertConflictSkipped;
|
||||
/**
|
||||
* Set true once controller.preDelete() has been invoked so that it is
|
||||
* only ever fired once (as it is fired early, prior to cascading the
|
||||
* delete to children/many's rather than as part of executing the delete).
|
||||
*/
|
||||
private boolean preDeleteCalled;
|
||||
private boolean preDeleteResult = true;
|
||||
|
||||
public PersistRequestBean(SpiEbeanServer server, T bean, Object parentBean, BeanManager<T> mgr, SpiTransaction t,
|
||||
PersistExecute persistExecute, PersistRequest.Type type, int flags) {
|
||||
@@ -1276,14 +1283,29 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
}
|
||||
|
||||
private int executeDelete() {
|
||||
setTenantId();
|
||||
if (controller == null || controller.preDelete(this)) {
|
||||
if (controllerPreDelete()) {
|
||||
return beanManager.getBeanPersister().delete(this);
|
||||
}
|
||||
// delete handled by the BeanController so return 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke controller.preDelete() if not already invoked.
|
||||
* <p>
|
||||
* This is called prior to cascading the delete to children (assoc many's /
|
||||
* many-to-many intersection rows) so that the persist controller can still
|
||||
* see those collections/relationships as they were before the cascade delete.
|
||||
*/
|
||||
public boolean controllerPreDelete() {
|
||||
if (!preDeleteCalled) {
|
||||
preDeleteCalled = true;
|
||||
setTenantId();
|
||||
preDeleteResult = controller == null || controller.preDelete(this);
|
||||
}
|
||||
return preDeleteResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist to the document store now (via buffer, not post commit).
|
||||
*/
|
||||
|
||||
@@ -907,6 +907,11 @@ public final class DefaultPersister implements Persister {
|
||||
* </p>
|
||||
*/
|
||||
private int delete(PersistRequestBean<?> request) {
|
||||
// fire preDelete now, before cascading to children/many's so that the
|
||||
// BeanPersistController/Adapter still sees the bean's collections and
|
||||
// relationships as they are prior to the cascade delete
|
||||
request.controllerPreDelete();
|
||||
|
||||
DeleteUnloadedForeignKeys unloadedForeignKeys = null;
|
||||
if (request.isPersistCascade()) {
|
||||
// delete children first ... register the
|
||||
|
||||
@@ -9,6 +9,9 @@ import io.ebean.event.BeanPersistRequest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.tests.model.m2m.MnyA;
|
||||
import org.tests.model.m2m.MnyB;
|
||||
import org.tests.model.m2m.MnyC;
|
||||
import org.tests.model.m2m.MnyTopic;
|
||||
import org.tests.model.basic.EBasicVer;
|
||||
import org.tests.model.basic.UTDetail;
|
||||
@@ -166,6 +169,56 @@ public class BeanPersistControllerTest {
|
||||
db.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preDelete_seesManyToManyCollection_beforeCascadeDelete() {
|
||||
List<List<MnyC>> capturedCs = new ArrayList<>();
|
||||
BeanPersistAdapter mnyBAdapter = new BeanPersistAdapter() {
|
||||
@Override
|
||||
public boolean isRegisterFor(Class<?> cls) {
|
||||
return MnyB.class.isAssignableFrom(cls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean preDelete(BeanPersistRequest<?> request) {
|
||||
// the M2M collection should still be intact here, before the
|
||||
// intersection table rows are cascade deleted
|
||||
capturedCs.add(new ArrayList<>(((MnyB) request.bean()).getCs()));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
DatabaseBuilder config = Database.builder();
|
||||
config.setName("h2ebasicver");
|
||||
config.setRegister(false);
|
||||
config.setDefaultServer(false);
|
||||
config.loadFromProperties();
|
||||
config.setDdlGenerate(true);
|
||||
config.setDdlRun(true);
|
||||
config.setDdlExtra(false);
|
||||
config.addClass(MnyA.class);
|
||||
config.addClass(MnyB.class);
|
||||
config.addClass(MnyC.class);
|
||||
config.add(mnyBAdapter);
|
||||
Database db = config.build();
|
||||
|
||||
try {
|
||||
MnyB mnyB = new MnyB();
|
||||
MnyC mnyC = new MnyC();
|
||||
mnyB.setCs(new ArrayList<>());
|
||||
mnyB.getCs().add(mnyC);
|
||||
db.save(mnyC);
|
||||
db.save(mnyB);
|
||||
|
||||
MnyB mnyBFromDB = db.find(MnyB.class, mnyB.getId());
|
||||
db.delete(mnyBFromDB);
|
||||
|
||||
assertThat(capturedCs).hasSize(1);
|
||||
assertThat(capturedCs.get(0)).extracting("id").containsExactly(mnyC.getId());
|
||||
} finally {
|
||||
db.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
private Database createDatabase(PersistAdapter persistAdapter) {
|
||||
DatabaseBuilder config = Database.builder();
|
||||
config.setName("h2ebasicver");
|
||||
|
||||
Reference in New Issue
Block a user