diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/DefaultPersister.java b/src/main/java/com/avaje/ebeaninternal/server/persist/DefaultPersister.java index 63c7f9b3a..5583366e7 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/persist/DefaultPersister.java +++ b/src/main/java/com/avaje/ebeaninternal/server/persist/DefaultPersister.java @@ -899,6 +899,13 @@ public final class DefaultPersister implements Persister { public boolean isPublish() { return publish; } + + private void resetModifyState() { + Object details = getValue(); + if (details instanceof BeanCollection) { + modifyListenReset((BeanCollection)details); + } + } } private void saveMany(SaveManyPropRequest saveMany, boolean insertMode) { @@ -906,9 +913,9 @@ public final class DefaultPersister implements Persister { if (saveMany.getMany().isManyToMany()) { // check if we can save the m2m intersection in this direction + // we only allow one direction based on first traversed basis boolean saveIntersectionFromThisDirection = saveMany.isSaveIntersection(); if (saveMany.isCascade()) { - // Need explicit Cascade to save the beans on other side saveAssocManyDetails(saveMany, false, insertMode); } // for ManyToMany save the 'relationship' via inserts/deletes @@ -916,6 +923,8 @@ public final class DefaultPersister implements Persister { if (saveIntersectionFromThisDirection) { // only allowed on one direction of a m2m based on beanName saveAssocManyIntersection(saveMany, saveMany.isDeleteMissingChildren()); + } else { + saveMany.resetModifyState(); } } else { if (saveMany.isModifyListenMode()) { diff --git a/src/test/java/com/avaje/tests/model/m2m/DCredit.java b/src/test/java/com/avaje/tests/model/m2m/DCredit.java new file mode 100644 index 000000000..a03291c23 --- /dev/null +++ b/src/test/java/com/avaje/tests/model/m2m/DCredit.java @@ -0,0 +1,49 @@ +package com.avaje.tests.model.m2m; + +import com.avaje.ebean.Model; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToMany; +import java.util.List; + +@Entity +public class DCredit extends Model { + + @Id + Long id; + + String credit; + + @ManyToMany(cascade = CascadeType.PERSIST) + List droles; + + public DCredit(String credit) { + this.credit = credit; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getCredit() { + return credit; + } + + public void setCredit(String credit) { + this.credit = credit; + } + + public List getDroles() { + return droles; + } + + public void setDroles(List droles) { + this.droles = droles; + } +} diff --git a/src/test/java/com/avaje/tests/model/m2m/DRol.java b/src/test/java/com/avaje/tests/model/m2m/DRol.java new file mode 100644 index 000000000..739f0e66f --- /dev/null +++ b/src/test/java/com/avaje/tests/model/m2m/DRol.java @@ -0,0 +1,56 @@ +package com.avaje.tests.model.m2m; + +import com.avaje.ebean.Model; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToMany; +import java.util.List; + +@Entity +public class DRol extends Model { + + @Id + Long id; + + final String name; + + @ManyToMany(mappedBy = "droles", cascade = CascadeType.PERSIST) + private List credits; + + @ManyToMany(mappedBy = "croles", cascade = CascadeType.PERSIST) + private List rots; + + public DRol(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public List getCredits() { + return credits; + } + + public void setCredits(List credits) { + this.credits = credits; + } + + public List getRots() { + return rots; + } + + public void setRots(List rots) { + this.rots = rots; + } +} diff --git a/src/test/java/com/avaje/tests/model/m2m/DRot.java b/src/test/java/com/avaje/tests/model/m2m/DRot.java new file mode 100644 index 000000000..67bda421b --- /dev/null +++ b/src/test/java/com/avaje/tests/model/m2m/DRot.java @@ -0,0 +1,46 @@ +package com.avaje.tests.model.m2m; + +import com.avaje.ebean.Model; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToMany; +import java.util.List; + + +@Entity +public class DRot extends Model { + + @Id + Long id; + + final String name; + + @ManyToMany(cascade = CascadeType.ALL) + List croles; + + public DRot(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public List getCroles() { + return croles; + } + + public void setCroles(List croles) { + this.croles = croles; + } +} diff --git a/src/test/java/com/avaje/tests/model/m2m/TestM2MDoubleInsert.java b/src/test/java/com/avaje/tests/model/m2m/TestM2MDoubleInsert.java new file mode 100644 index 000000000..1a4e0adcf --- /dev/null +++ b/src/test/java/com/avaje/tests/model/m2m/TestM2MDoubleInsert.java @@ -0,0 +1,23 @@ +package com.avaje.tests.model.m2m; + +import com.avaje.ebean.Ebean; +import org.junit.Test; + +public class TestM2MDoubleInsert { + + @Test + public void doubleInsert() { + + DRol role = new DRol("rol"); + role.save(); + + DCredit credit = new DCredit("x1"); + credit.getDroles().add(role); + role.getCredits().add(credit); + credit.save(); + + DRot rot = new DRot("rot"); + rot.getCroles().add(role); + Ebean.save(rot); + } +}