mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
#805 - ENH: Add BeanState.resetForInsert() ... This resets bean state such that a save() results in an insert
This commit is contained in:
@@ -120,4 +120,9 @@ public interface BeanState {
|
||||
* for a fully loaded entity bean.
|
||||
*/
|
||||
void setLoaded();
|
||||
|
||||
/**
|
||||
* Reset the bean putting it into NEW state such that a save() results in an insert.
|
||||
*/
|
||||
void resetForInsert();
|
||||
}
|
||||
@@ -342,6 +342,13 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
return state == STATE_LOADED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bean into NEW state.
|
||||
*/
|
||||
public void setNew() {
|
||||
this.state = STATE_NEW;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the loaded state to true.
|
||||
* <p>
|
||||
|
||||
@@ -29,10 +29,9 @@ public class ScopedTransaction implements SpiTransaction {
|
||||
|
||||
public ScopedTransaction(ScopeTrans scopeTrans) {
|
||||
this.scopeTrans = scopeTrans;
|
||||
this.transaction =scopeTrans.getTransaction();
|
||||
this.transaction = scopeTrans.getTransaction();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void commit() throws RollbackException {
|
||||
scopeTrans.commitTransaction();
|
||||
@@ -49,6 +48,11 @@ public class ScopedTransaction implements SpiTransaction {
|
||||
scopeTrans.rollback(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollbackIfActive() {
|
||||
transaction.rollbackIfActive();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRollbackOnly() {
|
||||
scopeTrans.setRollbackOnly();
|
||||
|
||||
@@ -220,6 +220,12 @@ public interface SpiTransaction extends Transaction {
|
||||
*/
|
||||
Connection getInternalConnection();
|
||||
|
||||
/**
|
||||
* Rollback if the transaction is active. This provides an internal
|
||||
* mechanism for rollback failures occur on commit().
|
||||
*/
|
||||
void rollbackIfActive();
|
||||
|
||||
/**
|
||||
* Return true if the manyToMany intersection should be persisted for this particular relationship direction.
|
||||
*/
|
||||
|
||||
@@ -68,11 +68,11 @@ public abstract class BeanRequest {
|
||||
public void rollbackTransIfRequired() {
|
||||
if (createdTransaction) {
|
||||
try {
|
||||
transaction.rollback();
|
||||
transaction.rollbackIfActive();
|
||||
} catch (Exception e) {
|
||||
// Just log this and carry on. A previous exception has been
|
||||
// thrown and if this rollback throws exception it likely means
|
||||
// that the connection is broken (and the datasource and db will cleanup)
|
||||
// that the connection is broken (and the dataSource and db will cleanup)
|
||||
log.error("Error trying to rollback a transaction (after a prior exception thrown)", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,4 +84,9 @@ public class DefaultBeanState implements BeanState {
|
||||
public boolean isDisableLazyLoad() {
|
||||
return intercept.isDisableLazyLoad();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetForInsert() {
|
||||
intercept.setNew();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -821,7 +821,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the bean to the TransactionEvent. This will be used by TransactionManager to synch Cache,
|
||||
* Add the bean to the TransactionEvent. This will be used by TransactionManager to sync Cache,
|
||||
* Cluster and text indexes.
|
||||
*/
|
||||
private void addEvent() {
|
||||
|
||||
@@ -41,7 +41,7 @@ final class TransWrapper {
|
||||
|
||||
void rollbackIfCreated() {
|
||||
if (wasCreated){
|
||||
transaction.rollback();
|
||||
transaction.rollbackIfActive();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -913,28 +913,27 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
throw new IllegalStateException(illegalStateMessage);
|
||||
}
|
||||
|
||||
firePreCommit();
|
||||
|
||||
try {
|
||||
if (queryOnly) {
|
||||
// can rollback or just close for performance
|
||||
connectionEndForQueryOnly();
|
||||
|
||||
} else {
|
||||
// commit
|
||||
if (batchControl != null && !batchControl.isEmpty()) {
|
||||
batchControl.flush();
|
||||
}
|
||||
firePreCommit();
|
||||
// only performCommit can throw an exception
|
||||
performCommit();
|
||||
firePostCommit();
|
||||
notifyCommit();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
doRollback(e);
|
||||
throw new RollbackException(e);
|
||||
|
||||
} finally {
|
||||
// these will not throw an exception
|
||||
firePostCommit();
|
||||
deactivate();
|
||||
notifyCommit();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -959,6 +958,16 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
this.rollbackOnly = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform rollback is the transaction is still active.
|
||||
*/
|
||||
@Override
|
||||
public void rollbackIfActive() {
|
||||
if (isActive()) {
|
||||
rollback(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback the transaction.
|
||||
*/
|
||||
@@ -976,17 +985,26 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
if (!isActive()) {
|
||||
throw new IllegalStateException(illegalStateMessage);
|
||||
}
|
||||
try {
|
||||
doRollback(cause);
|
||||
} finally {
|
||||
deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the jdbc rollback and fire any registered callbacks.
|
||||
*/
|
||||
private void doRollback(Throwable cause) {
|
||||
firePreRollback();
|
||||
try {
|
||||
performRollback();
|
||||
|
||||
} catch (Exception ex) {
|
||||
} catch (SQLException ex) {
|
||||
throw new PersistenceException(ex);
|
||||
|
||||
} finally {
|
||||
// these will not throw an exception
|
||||
firePostRollback();
|
||||
deactivate();
|
||||
notifyRollback(cause);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.avaje.tests.transaction;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.tests.model.m2m.MnyB;
|
||||
import com.avaje.tests.model.m2m.MnyC;
|
||||
import org.avaje.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestBeanStateReset extends BaseTestCase {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(TestBeanStateReset.class);
|
||||
|
||||
@Test
|
||||
public void resetForInsert() {
|
||||
|
||||
// setup to fail foreign key constraint
|
||||
MnyC c = new MnyC();
|
||||
c.setId(Long.MAX_VALUE);
|
||||
|
||||
MnyB b = new MnyB();
|
||||
b.getCs().add(c);
|
||||
|
||||
try {
|
||||
// inserts of b succeeds but intersection insert fails FK check on c
|
||||
b.save();
|
||||
|
||||
} catch (PersistenceException e) {
|
||||
logger.info("expected error " + e.getMessage());
|
||||
|
||||
Ebean.getBeanState(b).resetForInsert();
|
||||
b.getCs().clear();
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
b.setName("mod");
|
||||
b.save();
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql.get(0)).contains("insert into mny_b (id, name, version, when_created, when_modified, a_id) values (");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package com.avaje.tests.transaction;
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.TransactionCallbackAdapter;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -27,8 +28,9 @@ public class TestTransactionCallback extends BaseTestCase {
|
||||
public void test_commitAndRollback() {
|
||||
|
||||
|
||||
Ebean.beginTransaction();
|
||||
Transaction txn = Ebean.beginTransaction();
|
||||
Ebean.register(new MyCallback());
|
||||
txn.getConnection();
|
||||
Ebean.commitTransaction();
|
||||
|
||||
assertEquals(1, countPreCommit);
|
||||
|
||||
Reference in New Issue
Block a user