diff --git a/src/main/java/io/ebean/BeanRepository.java b/src/main/java/io/ebean/BeanRepository.java
index 3c588b65c..b926ea8a0 100644
--- a/src/main/java/io/ebean/BeanRepository.java
+++ b/src/main/java/io/ebean/BeanRepository.java
@@ -167,6 +167,30 @@ public abstract class BeanRepository extends BeanFinder {
return db().deletePermanent(bean);
}
+ /**
+ * Merge this entity using the default merge options.
+ *
+ * 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#merge(Object)
+ */
+ public void merge(T bean) {
+ db().merge(bean);
+ }
+
+ /**
+ * Merge this entity using the specified merge options.
+ *
+ * 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#merge(Object, MergeOptions)
+ */
+ public void merge(T bean, MergeOptions options) {
+ db().merge(bean, options);
+ }
+
/**
* Refreshes this entity from the database.
*
diff --git a/src/main/java/io/ebean/Ebean.java b/src/main/java/io/ebean/Ebean.java
index 97f895921..09d2d738b 100644
--- a/src/main/java/io/ebean/Ebean.java
+++ b/src/main/java/io/ebean/Ebean.java
@@ -638,6 +638,15 @@ public final class Ebean {
serverMgr.getDefaultServer().updateAll(beans);
}
+ /**
+ * Merge the bean using the default merge options.
+ *
+ * @param bean The bean to merge
+ */
+ public static void merge(Object bean) {
+ serverMgr.getDefaultServer().merge(bean);
+ }
+
/**
* Merge the bean using the given merge options.
*
diff --git a/src/main/java/io/ebean/EbeanServer.java b/src/main/java/io/ebean/EbeanServer.java
index 1b9157c1f..23b974591 100644
--- a/src/main/java/io/ebean/EbeanServer.java
+++ b/src/main/java/io/ebean/EbeanServer.java
@@ -1628,6 +1628,13 @@ public interface EbeanServer {
*/
void updateAll(Collection> beans, Transaction transaction) throws OptimisticLockException;
+ /**
+ * Merge the bean using the default merge options (no paths specified, default delete).
+ *
+ * @param bean The bean to merge
+ */
+ void merge(Object bean);
+
/**
* Merge the bean using the given merge options.
*
diff --git a/src/main/java/io/ebean/MergeOptionsBuilder.java b/src/main/java/io/ebean/MergeOptionsBuilder.java
index 10365346c..7193c681c 100644
--- a/src/main/java/io/ebean/MergeOptionsBuilder.java
+++ b/src/main/java/io/ebean/MergeOptionsBuilder.java
@@ -8,11 +8,20 @@ import java.util.Set;
*/
public class MergeOptionsBuilder {
+ private static final MOptions DEFAULT_OPTIONS = new MOptions();
+
private Set paths = new LinkedHashSet<>();
private boolean clientGeneratedIds;
- private boolean deletePermanent = true;
+ private boolean deletePermanent;
+
+ /**
+ * Return the default options.
+ */
+ public static MergeOptions defaultOptions() {
+ return DEFAULT_OPTIONS;
+ }
/**
* Add a path that will included in the merge.
@@ -57,6 +66,12 @@ public class MergeOptionsBuilder {
private final boolean deletePermanent;
private final Set paths;
+ private MOptions(){
+ this.clientGeneratedIds = false;
+ this.paths = new LinkedHashSet<>();
+ this.deletePermanent = false;
+ }
+
private MOptions(Set paths, boolean clientGeneratedIds, boolean deletePermanent) {
this.paths = paths;
this.clientGeneratedIds = clientGeneratedIds;
diff --git a/src/main/java/io/ebean/SqlUpdate.java b/src/main/java/io/ebean/SqlUpdate.java
index 87364334d..9884c095c 100644
--- a/src/main/java/io/ebean/SqlUpdate.java
+++ b/src/main/java/io/ebean/SqlUpdate.java
@@ -19,15 +19,17 @@ package io.ebean;
*
*
{@code
*
- * // example that uses 'named' parameters
- * String s = "UPDATE f_topic set post_count = :count where id = :id";
- * SqlUpdate update = Ebean.createSqlUpdate(s);
- * update.setParameter("id", 1);
- * update.setParameter("count", 50);
+ * // example that uses 'named' parameters
*
- * int modifiedCount = Ebean.execute(update);
+ * String s = "UPDATE f_topic set post_count = :count where id = :id";
*
- * String msg = "There were " + modifiedCount + " rows updated";
+ * SqlUpdate update = Ebean.createSqlUpdate(s);
+ * update.setParameter("id", 1);
+ * update.setParameter("count", 50);
+ *
+ * int modifiedCount = update.execute();
+ *
+ * String msg = "There were " + modifiedCount + " rows updated";
*
* }
*
@@ -57,6 +59,33 @@ package io.ebean;
*
* txn.commit();
* }
+ * }
+ *
+ * An alternative to the batch mode on the transaction is to use addBatch() and executeBatch() like:
+ *
+ * {@code
+ *
+ * try (Transaction txn = Ebean.beginTransaction()) {
+ *
+ * insert.setNextParameter(10000);
+ * insert.setNextParameter("hello");
+ * insert.setNextParameter("rob");
+ * insert.addBatch();
+ *
+ * insert.setNextParameter(10001);
+ * insert.setNextParameter("goodbye");
+ * insert.setNextParameter("rob");
+ * insert.addBatch();
+ *
+ * insert.setNextParameter(10002);
+ * insert.setNextParameter("chow");
+ * insert.setNextParameter("bob");
+ * insert.addBatch();
+ *
+ * int[] rows = insert.executeBatch();
+ *
+ * txn.commit();
+ * }
*
* }
*
@@ -83,6 +112,18 @@ public interface SqlUpdate {
*/
int execute();
+ /**
+ * Execute when addBatch() has been used to batch multiple bind executions.
+ *
+ * @return The row counts for each of the batched statements.
+ */
+ int[] executeBatch();
+
+ /**
+ * Add the statement to batch processing to then later execute via executeBatch().
+ */
+ void addBatch();
+
/**
* Return the generated key value.
*/
diff --git a/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java b/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java
index 8232773fc..a4d887365 100644
--- a/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java
+++ b/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java
@@ -268,4 +268,15 @@ public interface SpiEbeanServer extends EbeanServer, BeanLoader, BeanCollectionL
* Return true if a row for the bean type and id exists.
*/
boolean exists(Class> beanType, Object beanId, Transaction transaction);
+
+ /**
+ * Add to JDBC batch for later execution.
+ */
+ void addBatch(SpiSqlUpdate defaultSqlUpdate, SpiTransaction transaction);
+
+ /**
+ * Execute the batched statement.
+ */
+ int[] executeBatch(SpiSqlUpdate defaultSqlUpdate, SpiTransaction transaction);
+
}
diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java
index 1a904843b..c63638240 100644
--- a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java
+++ b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java
@@ -13,6 +13,7 @@ import io.ebean.FutureIds;
import io.ebean.FutureList;
import io.ebean.FutureRowCount;
import io.ebean.MergeOptions;
+import io.ebean.MergeOptionsBuilder;
import io.ebean.PagedList;
import io.ebean.PersistenceContextScope;
import io.ebean.ProfileLocation;
@@ -65,6 +66,7 @@ import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiJsonContext;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.SpiQuery.Type;
+import io.ebeaninternal.api.SpiSqlUpdate;
import io.ebeaninternal.api.SpiTransaction;
import io.ebeaninternal.api.SpiTransactionManager;
import io.ebeaninternal.api.TransactionEventTable;
@@ -919,6 +921,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
return new DefaultUpdateQuery<>(createQuery(beanType));
}
+ @Override
+ public void merge(Object bean) {
+ merge(bean, MergeOptionsBuilder.defaultOptions(), null);
+ }
+
@Override
public void merge(Object bean, MergeOptions options) {
merge(bean, options, null);
@@ -1961,6 +1968,16 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
return persister.executeSqlUpdate(updSql, t);
}
+ @Override
+ public void addBatch(SpiSqlUpdate sqlUpdate, SpiTransaction transaction) {
+ persister.addBatch(sqlUpdate, transaction);
+ }
+
+ @Override
+ public int[] executeBatch(SpiSqlUpdate sqlUpdate, SpiTransaction transaction) {
+ return persister.executeBatch(sqlUpdate, transaction);
+ }
+
/**
* Execute the updateSql.
*/
diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java b/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java
index 92e40b48b..d9d4e6500 100644
--- a/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java
+++ b/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java
@@ -1,11 +1,12 @@
package io.ebeaninternal.server.core;
import io.ebean.Ebean;
-import io.ebean.EbeanServer;
import io.ebean.SqlUpdate;
import io.ebean.Update;
import io.ebeaninternal.api.BindParams;
+import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiSqlUpdate;
+import io.ebeaninternal.api.SpiTransaction;
import java.io.Serializable;
@@ -26,7 +27,7 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
private static final long serialVersionUID = -6493829438421253102L;
- private transient final EbeanServer server;
+ private transient final SpiEbeanServer server;
/**
* The parameters used to bind to the sql.
@@ -69,6 +70,16 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
private Object generatedKey;
+ /**
+ * Set when batching explicitly used.
+ */
+ private boolean batched;
+
+ /**
+ * Transaction used for addBatch() executeBatch() processing.
+ */
+ private transient SpiTransaction transaction;
+
/**
* Create with server sql and bindParams object.
*
@@ -76,7 +87,7 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
* same time.
*
*/
- public DefaultSqlUpdate(EbeanServer server, String sql, BindParams bindParams) {
+ public DefaultSqlUpdate(SpiEbeanServer server, String sql, BindParams bindParams) {
this.server = server;
this.sql = sql;
this.bindParams = bindParams;
@@ -86,7 +97,7 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
* Create with a specific server. This means you can use the
* SqlUpdate.execute() method.
*/
- public DefaultSqlUpdate(EbeanServer server, String sql) {
+ public DefaultSqlUpdate(SpiEbeanServer server, String sql) {
this(server, sql, new BindParams());
}
@@ -111,6 +122,10 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
@Override
public int execute() {
if (server != null) {
+ if (batched) {
+ server.executeBatch(this, transaction);
+ return -1;
+ }
return server.execute(this);
} else {
// Hopefully this doesn't catch anyone out...
@@ -118,6 +133,34 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
}
}
+ @Override
+ public int[] executeBatch() {
+ if (server == null) {
+ throw new IllegalStateException("No EbeanServer set?");
+ }
+ if (!batched) {
+ throw new IllegalStateException("No prior addBatch() called?");
+ }
+ return server.executeBatch(this, transaction);
+ }
+
+
+ @Override
+ public void addBatch() {
+ if (server == null) {
+ throw new IllegalStateException("No EbeanServer set?");
+ }
+ if (transaction == null) {
+ transaction = server.currentServerTransaction();
+ if (transaction == null) {
+ throw new IllegalStateException("No current transaction? Must have a transaction to use addBatch()");
+ }
+ }
+
+ batched = true;
+ server.addBatch(this, transaction);
+ }
+
@Override
public Object getGeneratedKey() {
return generatedKey;
diff --git a/src/main/java/io/ebeaninternal/server/core/PersistRequestUpdateSql.java b/src/main/java/io/ebeaninternal/server/core/PersistRequestUpdateSql.java
index 202eb5141..6aa17970c 100644
--- a/src/main/java/io/ebeaninternal/server/core/PersistRequestUpdateSql.java
+++ b/src/main/java/io/ebeaninternal/server/core/PersistRequestUpdateSql.java
@@ -1,6 +1,5 @@
package io.ebeaninternal.server.core;
-import io.ebean.SqlUpdate;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiSqlUpdate;
import io.ebeaninternal.api.SpiTransaction;
@@ -27,15 +26,17 @@ public final class PersistRequestUpdateSql extends PersistRequest {
private String description;
+ private boolean addBatch;
+
/**
* Create.
*/
- public PersistRequestUpdateSql(SpiEbeanServer server, SqlUpdate sqlUpdate,
+ public PersistRequestUpdateSql(SpiEbeanServer server, SpiSqlUpdate sqlUpdate,
SpiTransaction t, PersistExecute persistExecute) {
super(server, t, persistExecute, sqlUpdate.getLabel());
this.type = Type.UPDATESQL;
- this.updateSql = (SpiSqlUpdate) sqlUpdate;
+ this.updateSql = sqlUpdate;
updateSql.reset();
}
@@ -44,11 +45,24 @@ public final class PersistRequestUpdateSql extends PersistRequest {
profileBase(EVT_UPDATESQL, offset, (short)0, flushCount);
}
+ /**
+ * Add this statement to JDBC batch for later execution.
+ */
+ public int addBatch() {
+ this.addBatch = true;
+ return executeOrQueue();
+ }
+
@Override
public int executeNow() {
return persistExecute.executeSqlUpdate(this);
}
+ @Override
+ public boolean isBatchThisRequest() {
+ return addBatch || super.isBatchThisRequest();
+ }
+
@Override
public int executeOrQueue() {
return executeStatement();
diff --git a/src/main/java/io/ebeaninternal/server/core/Persister.java b/src/main/java/io/ebeaninternal/server/core/Persister.java
index 82e46b856..20cbfcce4 100644
--- a/src/main/java/io/ebeaninternal/server/core/Persister.java
+++ b/src/main/java/io/ebeaninternal/server/core/Persister.java
@@ -8,6 +8,7 @@ import io.ebean.Transaction;
import io.ebean.Update;
import io.ebean.bean.EntityBean;
import io.ebean.meta.MetricVisitor;
+import io.ebeaninternal.api.SpiSqlUpdate;
import io.ebeaninternal.api.SpiTransaction;
import io.ebeaninternal.server.deploy.BeanDescriptor;
@@ -91,4 +92,14 @@ public interface Persister {
* Visit the metrics.
*/
void visitMetrics(MetricVisitor visitor);
+
+ /**
+ * Add the statement to JDBC batch for later execution via executeBatch.
+ */
+ void addBatch(SpiSqlUpdate sqlUpdate, SpiTransaction transaction);
+
+ /**
+ * Execute the associated batched statement.
+ */
+ int[] executeBatch(SpiSqlUpdate sqlUpdate, SpiTransaction transaction);
}
diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java
index 807fbf16b..ee277666b 100644
--- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java
+++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java
@@ -637,9 +637,9 @@ public class BeanDescriptor implements BeanType, STreeType {
*/
public void setEbeanServer(SpiEbeanServer ebeanServer) {
this.ebeanServer = ebeanServer;
- for (BeanPropertyAssocMany> aPropertiesMany : propertiesMany) {
+ for (BeanPropertyAssocMany> assocMany : propertiesMany) {
// used for creating lazy loading lists etc
- aPropertiesMany.setLoader(ebeanServer);
+ assocMany.setEbeanServer(ebeanServer);
}
}
diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java
index f3bf893bc..687cc9d84 100644
--- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java
+++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java
@@ -7,10 +7,10 @@ import io.ebean.Transaction;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.BeanCollection.ModifyListenMode;
import io.ebean.bean.BeanCollectionAdd;
-import io.ebean.bean.BeanCollectionLoader;
import io.ebean.bean.EntityBean;
import io.ebean.bean.PersistenceContext;
import io.ebean.text.PathProperties;
+import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.json.SpiJsonReader;
@@ -50,6 +50,8 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST
private final String intersectionPublishTable;
private final String intersectionDraftTable;
+ private IntersectionTable intersectionTable;
+
/**
* For ManyToMany this is the Inverse join used to build reference queries.
*/
@@ -352,10 +354,30 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST
* Set the lazy load server to help create reference collections (that lazy
* load on demand).
*/
- public void setLoader(BeanCollectionLoader loader) {
+ public void setEbeanServer(SpiEbeanServer server) {
if (help != null) {
- help.setLoader(loader);
+ help.setLoader(server);
}
+ if (manyToMany) {
+ intersectionTable = initIntersectionTable();
+ }
+ }
+
+ private IntersectionTable initIntersectionTable() {
+
+ IntersectionBuilder row = new IntersectionBuilder(intersectionPublishTable, intersectionDraftTable);
+ for (ExportedProperty exportedProperty : exportedProperties) {
+ row.addColumn(exportedProperty.getForeignDbColumn());
+ }
+ importedId.buildImport(row);
+ return row.build();
+ }
+
+ /**
+ * Return the intersection table helper.
+ */
+ public IntersectionTable intersectionTable() {
+ return intersectionTable;
}
/**
@@ -755,6 +777,20 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST
return intersectionDraftTable != null && !intersectionDraftTable.equals(intersectionPublishTable);
}
+ /**
+ * Bind the two side of a many to many to the given SqlUpdate.
+ */
+ public void intersectionBind(SqlUpdate sql, EntityBean parentBean, EntityBean other) {
+ if (embeddedExportedProperties) {
+ BeanProperty idProp = descriptor.getIdProperty();
+ parentBean = (EntityBean) idProp.getValue(parentBean);
+ }
+ for (ExportedProperty exportedProperty : exportedProperties) {
+ sql.setNextParameter(exportedProperty.getValue(parentBean));
+ }
+ importedId.bindImport(sql, other);
+ }
+
private void buildExport(IntersectionRow row, EntityBean parentBean) {
if (embeddedExportedProperties) {
diff --git a/src/main/java/io/ebeaninternal/server/deploy/IntersectionBuilder.java b/src/main/java/io/ebeaninternal/server/deploy/IntersectionBuilder.java
new file mode 100644
index 000000000..d5658bf14
--- /dev/null
+++ b/src/main/java/io/ebeaninternal/server/deploy/IntersectionBuilder.java
@@ -0,0 +1,85 @@
+package io.ebeaninternal.server.deploy;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper to build IntersectionTable.
+ */
+public class IntersectionBuilder {
+
+ private final String publishTable;
+ private final String draftTable;
+
+ private final List columns = new ArrayList<>();
+
+ IntersectionBuilder(String publishTable, String draftTable) {
+ this.publishTable = publishTable;
+ this.draftTable = draftTable;
+ }
+
+ public void addColumn(String column) {
+ columns.add(column);
+ }
+
+ public IntersectionTable build() {
+
+ String insertSql = insertSql(publishTable);
+ String deleteSql = deleteSql(publishTable);
+
+ String draftInsertSql;
+ String draftDeleteSql;
+ if (publishTable.equals(draftTable)) {
+ draftInsertSql = insertSql;
+ draftDeleteSql = deleteSql;
+ } else {
+ draftInsertSql = insertSql(draftTable);
+ draftDeleteSql = deleteSql(draftTable);
+ }
+
+ return new IntersectionTable(insertSql, deleteSql, draftInsertSql, draftDeleteSql);
+ }
+
+ private String insertSql(String tableName) {
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("insert into ").append(tableName).append(" (");
+
+ int count = 0;
+ for (String column : columns) {
+ if (count++ > 0) {
+ sb.append(", ");
+ }
+ sb.append(column);
+ }
+ sb.append(") values (");
+ for (int i = 0; i < count; i++) {
+ if (i > 0) {
+ sb.append(", ");
+ }
+ sb.append("?");
+ }
+ sb.append(")");
+
+ return sb.toString();
+ }
+
+ private String deleteSql(String tableName) {
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("delete from ").append(tableName);
+ sb.append(" where ");
+
+ int count = 0;
+ for (String column : columns) {
+ if (count++ > 0) {
+ sb.append(" and ");
+ }
+ sb.append(column);
+ sb.append(" = ?");
+ }
+
+ return sb.toString();
+ }
+
+}
diff --git a/src/main/java/io/ebeaninternal/server/deploy/IntersectionRow.java b/src/main/java/io/ebeaninternal/server/deploy/IntersectionRow.java
index a0d6f3beb..59c13838a 100644
--- a/src/main/java/io/ebeaninternal/server/deploy/IntersectionRow.java
+++ b/src/main/java/io/ebeaninternal/server/deploy/IntersectionRow.java
@@ -1,8 +1,8 @@
package io.ebeaninternal.server.deploy;
-import io.ebean.EbeanServer;
import io.ebean.SqlUpdate;
import io.ebeaninternal.api.BindParams;
+import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.server.core.DefaultSqlUpdate;
import io.ebeaninternal.server.expression.DefaultExpressionRequest;
import io.ebeaninternal.server.expression.IdInExpression;
@@ -22,12 +22,12 @@ public class IntersectionRow {
private List excludeIds;
private BeanDescriptor> excludeDescriptor;
- public IntersectionRow(String tableName, BeanDescriptor> targetDescriptor) {
+ IntersectionRow(String tableName, BeanDescriptor> targetDescriptor) {
this.tableName = tableName;
this.targetDescriptor = targetDescriptor;
}
- public IntersectionRow(String tableName) {
+ IntersectionRow(String tableName) {
this.tableName = tableName;
this.targetDescriptor = null;
}
@@ -35,7 +35,7 @@ public class IntersectionRow {
/**
* Set Id's to exclude. This is for deleting non-attached detail Id's.
*/
- public void setExcludeIds(List excludeIds, BeanDescriptor> excludeDescriptor) {
+ void setExcludeIds(List excludeIds, BeanDescriptor> excludeDescriptor) {
this.excludeIds = excludeIds;
this.excludeDescriptor = excludeDescriptor;
}
@@ -44,7 +44,7 @@ public class IntersectionRow {
values.put(key, value);
}
- public SqlUpdate createInsert(EbeanServer server) {
+ public SqlUpdate createInsert(SpiEbeanServer server) {
BindParams bindParams = new BindParams();
@@ -72,7 +72,7 @@ public class IntersectionRow {
return new DefaultSqlUpdate(server, sb.toString(), bindParams);
}
- public SqlUpdate createDelete(EbeanServer server, boolean softDelete) {
+ public SqlUpdate createDelete(SpiEbeanServer server, boolean softDelete) {
BindParams bindParams = new BindParams();
@@ -107,7 +107,7 @@ public class IntersectionRow {
return new DefaultSqlUpdate(server, sb.toString(), bindParams);
}
- public SqlUpdate createDeleteChildren(EbeanServer server) {
+ public SqlUpdate createDeleteChildren(SpiEbeanServer server) {
BindParams bindParams = new BindParams();
diff --git a/src/main/java/io/ebeaninternal/server/deploy/IntersectionTable.java b/src/main/java/io/ebeaninternal/server/deploy/IntersectionTable.java
new file mode 100644
index 000000000..785c2be4c
--- /dev/null
+++ b/src/main/java/io/ebeaninternal/server/deploy/IntersectionTable.java
@@ -0,0 +1,34 @@
+package io.ebeaninternal.server.deploy;
+
+import io.ebean.EbeanServer;
+import io.ebean.SqlUpdate;
+
+public class IntersectionTable {
+
+ private final String insertSql;
+ private final String deleteSql;
+ private final String draftInsertSql;
+ private final String draftDeleteSql;
+
+ IntersectionTable(String insertSql, String deleteSql, String draftInsertSql, String draftDeleteSql) {
+ this.insertSql = insertSql;
+ this.deleteSql = deleteSql;
+ this.draftInsertSql = draftInsertSql;
+ this.draftDeleteSql = draftDeleteSql;
+ }
+
+ /**
+ * Return a SqlUpdate for inserting into the intersection table.
+ */
+ public SqlUpdate insert(EbeanServer server, boolean draft) {
+ return server.createSqlUpdate(draft ? draftInsertSql : insertSql);
+ }
+
+ /**
+ * Return a SqlUpdate for deleting from the intersection table.
+ */
+ public SqlUpdate delete(EbeanServer server, boolean draft) {
+ return server.createSqlUpdate(draft ? draftDeleteSql : deleteSql);
+ }
+
+}
diff --git a/src/main/java/io/ebeaninternal/server/deploy/id/ImportedId.java b/src/main/java/io/ebeaninternal/server/deploy/id/ImportedId.java
index 422b0c41f..24b7c1bfe 100644
--- a/src/main/java/io/ebeaninternal/server/deploy/id/ImportedId.java
+++ b/src/main/java/io/ebeaninternal/server/deploy/id/ImportedId.java
@@ -4,6 +4,7 @@ import io.ebean.SqlUpdate;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.DbSqlContext;
+import io.ebeaninternal.server.deploy.IntersectionBuilder;
import io.ebeaninternal.server.deploy.IntersectionRow;
import io.ebeaninternal.server.persist.dml.GenerateDmlRequest;
import io.ebeaninternal.server.persist.dmlbind.BindableRequest;
@@ -66,4 +67,14 @@ public interface ImportedId {
* Return the set importedId clause.
*/
String importedIdClause();
+
+ /**
+ * Add DB columns to the intersection builder.
+ */
+ void buildImport(IntersectionBuilder row);
+
+ /**
+ * Bind values to the intersection SqlUpdate.
+ */
+ void bindImport(SqlUpdate sql, EntityBean other);
}
diff --git a/src/main/java/io/ebeaninternal/server/deploy/id/ImportedIdEmbedded.java b/src/main/java/io/ebeaninternal/server/deploy/id/ImportedIdEmbedded.java
index 1a37c7f52..22c80dfc9 100644
--- a/src/main/java/io/ebeaninternal/server/deploy/id/ImportedIdEmbedded.java
+++ b/src/main/java/io/ebeaninternal/server/deploy/id/ImportedIdEmbedded.java
@@ -7,6 +7,7 @@ import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BeanPropertyAssoc;
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import io.ebeaninternal.server.deploy.DbSqlContext;
+import io.ebeaninternal.server.deploy.IntersectionBuilder;
import io.ebeaninternal.server.deploy.IntersectionRow;
import io.ebeaninternal.server.persist.dml.GenerateDmlRequest;
import io.ebeaninternal.server.persist.dmlbind.BindableRequest;
@@ -130,15 +131,31 @@ public class ImportedIdEmbedded implements ImportedId {
EntityBean embeddedId = (EntityBean) foreignAssocOne.getValue(other);
if (embeddedId == null) {
- String msg = "Foreign Key value null?";
- throw new PersistenceException(msg);
+ throw new PersistenceException("Foreign Key value null?");
}
-
for (ImportedIdSimple anImported : imported) {
Object scalarValue = anImported.foreignProperty.getValue(embeddedId);
row.put(anImported.localDbColumn, scalarValue);
}
+ }
+ @Override
+ public void buildImport(IntersectionBuilder row) {
+ for (ImportedIdSimple importedScalar : imported) {
+ row.addColumn(importedScalar.localDbColumn);
+ }
+ }
+
+ @Override
+ public void bindImport(SqlUpdate sql, EntityBean other) {
+ EntityBean embeddedId = (EntityBean) foreignAssocOne.getValue(other);
+ if (embeddedId == null) {
+ throw new PersistenceException("Foreign Key value null?");
+ }
+ for (ImportedIdSimple anImported : imported) {
+ Object scalarValue = anImported.foreignProperty.getValue(embeddedId);
+ sql.setNextParameter(scalarValue);
+ }
}
/**
diff --git a/src/main/java/io/ebeaninternal/server/deploy/id/ImportedIdSimple.java b/src/main/java/io/ebeaninternal/server/deploy/id/ImportedIdSimple.java
index 803ff4b56..e84b07e49 100644
--- a/src/main/java/io/ebeaninternal/server/deploy/id/ImportedIdSimple.java
+++ b/src/main/java/io/ebeaninternal/server/deploy/id/ImportedIdSimple.java
@@ -7,6 +7,7 @@ import io.ebeaninternal.server.deploy.BeanFkeyProperty;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BeanPropertyAssoc;
import io.ebeaninternal.server.deploy.DbSqlContext;
+import io.ebeaninternal.server.deploy.IntersectionBuilder;
import io.ebeaninternal.server.deploy.IntersectionRow;
import io.ebeaninternal.server.persist.dml.GenerateDmlRequest;
import io.ebeaninternal.server.persist.dmlbind.BindableRequest;
@@ -98,6 +99,20 @@ public final class ImportedIdSimple implements ImportedId, Comparable