diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/id/IdBinder.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/id/IdBinder.java index 77982beccf..01aa079df6 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/id/IdBinder.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/id/IdBinder.java @@ -59,6 +59,13 @@ public interface IdBinder { */ boolean isComplexId(); + /** + * Return the number of properties that make up the id. + */ + default int size() { + return 1; + } + /** * Return the default order by that may need to be used if the query includes * a many property. diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/id/IdBinderEmbedded.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/id/IdBinderEmbedded.java index dec75f0015..ae3353aa91 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/id/IdBinderEmbedded.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/id/IdBinderEmbedded.java @@ -114,6 +114,11 @@ public boolean isComplexId() { return true; } + @Override + public int size() { + return props.length; + } + @Override public String orderBy() { return orderBy(null, true); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java b/ebean-core/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java index 8cb2eef030..a923adb2e8 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java @@ -58,7 +58,7 @@ public DefaultPersister(SpiEbeanServer server, Binder binder, BeanDescriptorMana * e.g. SqlServer has a 2100 parameter limit, so delete max 2000 for it. */ private int initMaxDeleteBatch(int maxInBinding) { - return maxInBinding == 0 ? 1000 : maxInBinding; + return maxInBinding == 0 ? 1000 : Math.min(1000, maxInBinding); } @Override @@ -652,11 +652,9 @@ public int deleteByIds(BeanDescriptor descriptor, List idList, Transa } private int delete(BeanDescriptor descriptor, List idList, Transaction transaction, DeleteMode deleteMode) { - if (idList == null || idList.size() <= maxDeleteBatch) { - return new DeleteBatchHelpMultiple(descriptor, idList, transaction, deleteMode).deleteBatch(); - } + final int batch = maxDeleteBatch / descriptor.idBinder().size(); int rows = 0; - for (List batchOfIds : Lists.partition(idList, maxDeleteBatch)) { + for (List batchOfIds : Lists.partition(idList, batch)) { rows += new DeleteBatchHelpMultiple(descriptor, batchOfIds, transaction, deleteMode).deleteBatch(); } return rows; @@ -1079,35 +1077,32 @@ private void deleteAssocMany(PersistRequestBean request) { * For stateless updates this deletes details beans that are no longer in * the many - the excludeDetailIds holds the detail beans that are in the * collection (and should not be deleted). - *

*/ void deleteManyDetails(SpiTransaction t, BeanDescriptor desc, EntityBean parentBean, BeanPropertyAssocMany many, Set excludeDetailIds, DeleteMode deleteMode) { if (many.cascadeInfo().isDelete()) { // cascade delete the beans in the collection - BeanDescriptor targetDesc = many.targetDescriptor(); + final BeanDescriptor targetDesc = many.targetDescriptor(); + final int batch = maxDeleteBatch / targetDesc.idBinder().size(); if (deleteMode.isHard() || targetDesc.isSoftDelete()) { if (targetDesc.isDeleteByStatement() - && (excludeDetailIds == null || excludeDetailIds.size() <= maxDeleteBatch)) { // TODO wait for #3176 + && (excludeDetailIds == null || excludeDetailIds.size() <= batch)) { // Just delete all the children with one statement IntersectionRow intRow = many.buildManyDeleteChildren(parentBean, excludeDetailIds); SqlUpdate sqlDelete = intRow.createDelete(server, deleteMode); executeSqlUpdate(sqlDelete, t); } else { - // TODO: Review first checking if many property is loaded and using the loaded beans - // ... and only using findIdsByParentId() when the many property isn't loaded // Delete recurse using the Id values of the children Object parentId = desc.getId(parentBean); List idsByParentId; - if (excludeDetailIds == null || excludeDetailIds.size() <= maxDeleteBatch) { // TODO: Wait for #3176 + if (excludeDetailIds == null || excludeDetailIds.size() <= batch) { idsByParentId = many.findIdsByParentId(parentId, t, deleteMode.isHard(), excludeDetailIds); } else { - // if we hit the parameter limit, we must filter that on the java side. - // There is no easy way to batch "not in" queries. - // checkme: We could pass the first 1000-2000 params to the DB and filter the rest + // if we hit the parameter limit, we must filter that on the java side + // as there is no easy way to batch "not in" queries. idsByParentId = many.findIdsByParentId(parentId, t, deleteMode.isHard(), null); - idsByParentId.removeIf(id -> excludeDetailIds.contains(id)); + idsByParentId.removeIf(excludeDetailIds::contains); } if (!idsByParentId.isEmpty()) { deleteChildrenById(t, targetDesc, idsByParentId, deleteMode);