HHH-9195 - Adding an entity at a given index in a list annotated with OrderColumn adds the entity at the end

This commit is contained in:
Steve Ebersole 2015-11-04 13:02:26 -06:00
parent 71e13cdf25
commit 30d7c800bd
4 changed files with 47 additions and 26 deletions

View File

@ -371,12 +371,16 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
return cachedSize; return cachedSize;
} }
private boolean isConnectedToSession() { protected boolean isConnectedToSession() {
return session != null return session != null
&& session.isOpen() && session.isOpen()
&& session.getPersistenceContext().containsCollection( this ); && session.getPersistenceContext().containsCollection( this );
} }
protected boolean isInitialized() {
return initialized;
}
/** /**
* Called by any writer method of the collection interface * Called by any writer method of the collection interface
*/ */
@ -424,7 +428,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
* Is this the "inverse" end of a bidirectional association? * Is this the "inverse" end of a bidirectional association?
*/ */
@SuppressWarnings({"JavaDoc"}) @SuppressWarnings({"JavaDoc"})
private boolean isInverseCollection() { protected boolean isInverseCollection() {
final CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this ); final CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
return ce != null && ce.getLoadedPersister().isInverse(); return ce != null && ce.getLoadedPersister().isInverse();
} }
@ -434,7 +438,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
* no orphan delete enabled? * no orphan delete enabled?
*/ */
@SuppressWarnings({"JavaDoc"}) @SuppressWarnings({"JavaDoc"})
private boolean isInverseCollectionNoOrphanDelete() { protected boolean isInverseCollectionNoOrphanDelete() {
final CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this ); final CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
return ce != null return ce != null
&& &&
@ -447,7 +451,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
* of a collection with no orphan delete? * of a collection with no orphan delete?
*/ */
@SuppressWarnings({"JavaDoc"}) @SuppressWarnings({"JavaDoc"})
private boolean isInverseOneToManyOrNoOrphanDelete() { protected boolean isInverseOneToManyOrNoOrphanDelete() {
final CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this ); final CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
return ce != null return ce != null
&& ce.getLoadedPersister().isInverse() && ce.getLoadedPersister().isInverse()

View File

@ -14,6 +14,7 @@ import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import java.util.Map;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.SessionImplementor;
@ -314,7 +315,12 @@ public class PersistentList extends AbstractPersistentCollection implements List
if ( index < 0 ) { if ( index < 0 ) {
throw new ArrayIndexOutOfBoundsException( "negative index" ); throw new ArrayIndexOutOfBoundsException( "negative index" );
} }
if ( !isOperationQueueEnabled() ) { if ( !isInitialized() && isConnectedToSession() ) {
// NOTE : we don't care about the inverse part here because
// even if the collection is inverse, this side is driving the
// writing of the indexes. And because this is a positioned-add
// we need to load the underlying elements to know how that
// affects overall re-ordering
write(); write();
list.add( index, value ); list.add( index, value );
} }

View File

@ -289,6 +289,8 @@ public abstract class AbstractFlushingEventListener implements Serializable {
) )
); );
} }
// todo : I'm not sure the !wasInitialized part should really be part of this check
if ( !coll.wasInitialized() && coll.hasQueuedOperations() ) { if ( !coll.wasInitialized() && coll.hasQueuedOperations() ) {
actionQueue.addAction( actionQueue.addAction(
new QueuedOperationCollectionAction( new QueuedOperationCollectionAction(

View File

@ -18,16 +18,19 @@ import javax.persistence.OrderColumn;
import javax.persistence.Table; import javax.persistence.Table;
import org.hibernate.Hibernate; import org.hibernate.Hibernate;
import org.hibernate.LazyInitializationException;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.Transaction; import org.hibernate.Transaction;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.testing.FailureExpected;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.fail;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
@ -70,31 +73,24 @@ public class ListAddTest extends BaseNonConfigCoreFunctionalTestCase {
* This test fails, but shouldn't * This test fails, but shouldn't
*/ */
@Test @Test
@FailureExpected( jiraKey = "HHH-9195" )
public void addQuestionWithIndexShouldAddQuestionAtSpecifiedIndex() { public void addQuestionWithIndexShouldAddQuestionAtSpecifiedIndex() {
Session session = openSession(); Session session = openSession();
Transaction transaction = session.beginTransaction(); Transaction transaction = session.beginTransaction();
Quizz quizz = session.get( Quizz.class, 1 ); Quizz quizz = session.get( Quizz.class, 1 );
quizz.addQuestion( 1, new Question( 4, "question that should be at index 1" ) ); quizz.addQuestion( 1, new Question( 4, "question that should be at index 1" ) );
transaction.commit(); transaction.commit();
session.close(); session.close();
session = openSession(); session = openSession();
transaction = session.beginTransaction(); transaction = session.beginTransaction();
quizz = session.get( Quizz.class, 1); quizz = session.get( Quizz.class, 1);
assertEquals( 4, quizz.getQuestions().size() ); assertEquals( 4, quizz.getQuestions().size() );
assertEquals( 4, quizz.getQuestions().get( 1 ).getId().longValue() ); assertEquals( 4, quizz.getQuestions().get( 1 ).getId().longValue() );
transaction.commit(); transaction.commit();
session.close(); session.close();
} }
@Test @Test
@FailureExpected( jiraKey = "HHH-9195" )
public void addQuestionToDetachedQuizz() { public void addQuestionToDetachedQuizz() {
Session session = openSession(); Session session = openSession();
session.beginTransaction(); session.beginTransaction();
@ -102,21 +98,34 @@ public class ListAddTest extends BaseNonConfigCoreFunctionalTestCase {
session.getTransaction().commit(); session.getTransaction().commit();
session.close(); session.close();
quizz.addQuestion( 1, new Question( 4, "question that should be at index 1" ) ); assertFalse( ( (PersistentCollection) quizz.getQuestions() ).wasInitialized() );
session = openSession(); try {
session.beginTransaction(); // this is the crux of the comment on HHH-9195 in regard to uninitialized, detached collections and
session.merge( quizz ); // not allowing additions
session.getTransaction().commit(); quizz.addQuestion( new Question( 4, "question 4" ) );
session.close();
session = openSession(); // indexed-addition should fail
session.getTransaction().begin(); quizz.addQuestion( 1, new Question( 5, "question that should be at index 1" ) );
quizz = session.get( Quizz.class, 1); fail( "Expecting a failure" );
assertEquals( 4, quizz.getQuestions().size() ); }
assertEquals( 4, quizz.getQuestions().get( 1 ).getId().longValue() ); catch (LazyInitializationException ignore) {
session.getTransaction().commit(); // expected
session.close(); }
// session = openSession();
// session.beginTransaction();
// session.merge( quizz );
// session.getTransaction().commit();
// session.close();
//
// session = openSession();
// session.getTransaction().begin();
// quizz = session.get( Quizz.class, 1);
// assertEquals( 5, quizz.getQuestions().size() );
// assertEquals( 5, quizz.getQuestions().get( 1 ).getId().longValue() );
// session.getTransaction().commit();
// session.close();
} }
/** /**