Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#1503][#1566] Fixes & tests for orphanRemoval bugs #781

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 29 additions & 19 deletions framework/src/play/db/jpa/JPABase.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
import org.hibernate.collection.internal.PersistentMap;
import org.hibernate.engine.spi.*;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;
import org.hibernate.exception.GenericJDBCException;
import org.hibernate.internal.SessionImpl;
import org.hibernate.proxy.HibernateProxy;
Expand Down Expand Up @@ -137,24 +140,24 @@ private void saveAndCascade(boolean willBeSaved) {
continue;
}
if (value instanceof PersistentMap) {
if (((PersistentMap) value).wasInitialized()) {
cascadeOrphans(this, (PersistentCollection) value, willBeSaved);

cascadeOrphans(this, (PersistentCollection) value, willBeSaved);

for (Object o : ((Map) value).values()) {
saveAndCascadeIfJPABase(o, willBeSaved);
}
for (Object o : ((Map) value).values()) {
saveAndCascadeIfJPABase(o, willBeSaved);
}
continue;
}
if (value instanceof PersistentCollection) {
if (((PersistentCollection) value).wasInitialized()) {

cascadeOrphans(this, (PersistentCollection) value, willBeSaved);
cascadeOrphans(this, (PersistentCollection) value, willBeSaved);

for (Object o : (Collection) value) {
saveAndCascadeIfJPABase(o, willBeSaved);
}
for (Object o : (Collection) value) {
saveAndCascadeIfJPABase(o, willBeSaved);
}
continue;
}
if (value instanceof Collection) {
for (Object o : (Collection) value) {
saveAndCascadeIfJPABase(o, willBeSaved);
}
continue;
}
Expand All @@ -177,16 +180,23 @@ private void saveAndCascade(boolean willBeSaved) {

private void cascadeOrphans(JPABase base, PersistentCollection persistentCollection, boolean willBeSaved) {
String dbName = JPA.getDBName(this.getClass());

PersistenceContext pc = ((SessionImpl) JPA.em(dbName).getDelegate()).getPersistenceContext();

SessionImpl session = ((SessionImpl) JPA.em(dbName).getDelegate());
PersistenceContext pc = session.getPersistenceContext();
CollectionEntry ce = pc.getCollectionEntry(persistentCollection);

if (ce != null) {
EntityEntry entry = pc.getEntry(base);
if (entry != null) {
Collection orphans = ce.getOrphans(entry.getEntityName(), persistentCollection);
for (Object o : orphans) {
saveAndCascadeIfJPABase(o, willBeSaved);
CollectionPersister cp = ce.getLoadedPersister();
if (cp != null) {
Type ct = cp.getElementType();
if (ct instanceof EntityType) {
String entityName = ((EntityType) ct).getAssociatedEntityName(session.getFactory());
if (ce.getSnapshot() != null) {
Collection orphans = ce.getOrphans(entityName, persistentCollection);
for (Object o : orphans) {
saveAndCascadeIfJPABase(o, willBeSaved);
}
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import java.util.ArrayList;
Expand All @@ -16,4 +17,6 @@ public class BaseModel extends Model {
@OneToMany(mappedBy = "baseModel", cascade = CascadeType.ALL, orphanRemoval = true)
public List<LevelOne> levelOnes = new ArrayList<LevelOne>();

@ManyToOne
public LevelOne parent;
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,7 @@ public class LevelOne extends Model {
@OneToMany(mappedBy = "levelOne", cascade = CascadeType.ALL, orphanRemoval = true)
public List<LevelTwo> levelTwos = new ArrayList<LevelTwo>();

@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
public List<BaseModel> children = new ArrayList<BaseModel>();

}
77 changes: 77 additions & 0 deletions samples-and-tests/just-test-cases/test/JPABaseTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import models.orphans.collections.BaseModel;
import models.orphans.collections.LevelOne;
import models.orphans.collections.LevelTwo;
import org.junit.Ignore;
import org.junit.Test;
import play.db.jpa.JPA;
import play.db.jpa.JPAPlugin;
import play.test.UnitTest;

public class JPABaseTest extends UnitTest {

private void commit() {
try {
JPA.em().getTransaction().commit();
} finally {
JPA.em().getTransaction().begin();
}
}

private void commitAndClear() {
try {
JPAPlugin.closeTx(false);
} finally {
JPAPlugin.startTx(false);
}
}

@Test
public void testCollectionOwnerError() {
BaseModel bmA = new BaseModel();
bmA.save();
commitAndClear();

bmA = BaseModel.findById(bmA.id);

LevelOne levelOneA = new LevelOne();
levelOneA.baseModel = bmA;
bmA.levelOnes.add(levelOneA);

LevelTwo levelTwo = new LevelTwo();
levelTwo.levelOne = levelOneA;
levelOneA.levelTwos.add(levelTwo);

LevelOne levelOneB = new LevelOne();
levelOneB.baseModel = bmA;
bmA.levelOnes.add(levelOneB);

bmA.save();
commitAndClear();

bmA = BaseModel.findById(bmA.id);

LevelOne removed = bmA.levelOnes.remove(0);
bmA.save();

JPA.em().flush(); // where bug actually occurs
}

@Test
public void testDuplicateError() {
BaseModel bmA = new BaseModel();
bmA.save();
commit();

LevelOne levelOneA = new LevelOne();
levelOneA.baseModel = bmA;
bmA.levelOnes.add(levelOneA);

BaseModel bmB = new BaseModel();
bmB.parent = levelOneA;
levelOneA.children.add(bmB);

bmA.save();
commit();
}

}