Skip to content

Commit ad2639f

Browse files
committed
HHH-8083 @OrderColumn not updated on @onetomany cascade
Conflicts: hibernate-core/src/main/java/org/hibernate/action/internal/CollectionUpdateAction.java
1 parent 2a23b9f commit ad2639f

File tree

13 files changed

+412
-6
lines changed

13 files changed

+412
-6
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
5+
* indicated by the @author tags or express copyright attribution
6+
* statements applied by the authors. All third-party contributions are
7+
* distributed under license by Red Hat Inc.
8+
*
9+
* This copyrighted material is made available to anyone wishing to use, modify,
10+
* copy, or redistribute it subject to the terms and conditions of the GNU
11+
* Lesser General Public License, as published by the Free Software Foundation.
12+
*
13+
* This program is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15+
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
16+
* for more details.
17+
*
18+
* You should have received a copy of the GNU Lesser General Public License
19+
* along with this distribution; if not, write to:
20+
* Free Software Foundation, Inc.
21+
* 51 Franklin Street, Fifth Floor
22+
* Boston, MA 02110-1301 USA
23+
*/
24+
package org.hibernate.action.internal;
25+
26+
import java.io.Serializable;
27+
28+
import org.hibernate.HibernateException;
29+
import org.hibernate.collection.spi.PersistentCollection;
30+
import org.hibernate.engine.spi.SessionImplementor;
31+
import org.hibernate.persister.collection.CollectionPersister;
32+
33+
/**
34+
* If a collection is extra lazy and has queued ops, we still need to
35+
* process them. Ex: OneToManyPersister needs to insert indexes for List
36+
* collections. See HHH-8083.
37+
*
38+
* @author Brett Meyer
39+
*/
40+
public final class QueuedOperationCollectionAction extends CollectionAction {
41+
42+
/**
43+
* Constructs a CollectionUpdateAction
44+
*
45+
* @param collection The collection to update
46+
* @param persister The collection persister
47+
* @param id The collection key
48+
* @param session The session
49+
*/
50+
public QueuedOperationCollectionAction(
51+
final PersistentCollection collection,
52+
final CollectionPersister persister,
53+
final Serializable id,
54+
final SessionImplementor session) {
55+
super( persister, collection, id, session );
56+
}
57+
58+
@Override
59+
public void execute() throws HibernateException {
60+
final Serializable id = getKey();
61+
final SessionImplementor session = getSession();
62+
final CollectionPersister persister = getPersister();
63+
final PersistentCollection collection = getCollection();
64+
65+
persister.processQueuedOps( collection, id, session );
66+
}
67+
}
68+
69+
70+
71+
72+
73+
74+

hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import org.hibernate.action.internal.EntityIdentityInsertAction;
5353
import org.hibernate.action.internal.EntityInsertAction;
5454
import org.hibernate.action.internal.EntityUpdateAction;
55+
import org.hibernate.action.internal.QueuedOperationCollectionAction;
5556
import org.hibernate.action.internal.UnresolvedEntityInsertActions;
5657
import org.hibernate.action.spi.AfterTransactionCompletionProcess;
5758
import org.hibernate.action.spi.BeforeTransactionCompletionProcess;
@@ -63,7 +64,7 @@
6364

6465
/**
6566
* Responsible for maintaining the queue of actions related to events.
66-
* </p>
67+
*
6768
* The ActionQueue holds the DML operations queued as part of a session's
6869
* transactional-write-behind semantics. DML operations are queued here
6970
* until a flush forces them to be executed against the database.
@@ -91,6 +92,7 @@ public class ActionQueue {
9192
// just re-use the same Lists for convenience.
9293
private ArrayList collectionCreations;
9394
private ArrayList collectionUpdates;
95+
private ArrayList collectionQueuedOps;
9496
private ArrayList collectionRemovals;
9597

9698
private AfterTransactionCompletionProcessQueue afterTransactionProcesses;
@@ -115,6 +117,7 @@ private void init() {
115117
collectionCreations = new ArrayList( INIT_QUEUE_LIST_SIZE );
116118
collectionRemovals = new ArrayList( INIT_QUEUE_LIST_SIZE );
117119
collectionUpdates = new ArrayList( INIT_QUEUE_LIST_SIZE );
120+
collectionQueuedOps = new ArrayList( INIT_QUEUE_LIST_SIZE );
118121

119122
afterTransactionProcesses = new AfterTransactionCompletionProcessQueue( session );
120123
beforeTransactionProcesses = new BeforeTransactionCompletionProcessQueue( session );
@@ -128,6 +131,7 @@ public void clear() {
128131
collectionCreations.clear();
129132
collectionRemovals.clear();
130133
collectionUpdates.clear();
134+
collectionQueuedOps.clear();
131135

132136
unresolvedInsertions.clear();
133137
}
@@ -163,6 +167,11 @@ public void addAction(CollectionUpdateAction action) {
163167
collectionUpdates.add( action );
164168
}
165169

170+
@SuppressWarnings({ "unchecked" })
171+
public void addAction(QueuedOperationCollectionAction action) {
172+
collectionQueuedOps.add( action );
173+
}
174+
166175
@SuppressWarnings({ "unchecked" })
167176
public void addAction(EntityIdentityInsertAction insert) {
168177
LOG.tracev( "Adding an EntityIdentityInsertAction for [{0}] object", insert.getEntityName() );
@@ -276,6 +285,8 @@ public void executeActions() throws HibernateException {
276285
}
277286
executeActions( insertions );
278287
executeActions( updates );
288+
// do before actions are handled in the other collection queues
289+
executeActions( collectionQueuedOps );
279290
executeActions( collectionRemovals );
280291
executeActions( collectionUpdates );
281292
executeActions( collectionCreations );
@@ -291,6 +302,7 @@ public void prepareActions() throws HibernateException {
291302
prepareActions( collectionRemovals );
292303
prepareActions( collectionUpdates );
293304
prepareActions( collectionCreations );
305+
prepareActions( collectionQueuedOps );
294306
}
295307

296308
/**
@@ -325,6 +337,7 @@ public boolean areTablesToBeUpdated(Set tables) {
325337
areTablesToUpdated( deletions, tables ) ||
326338
areTablesToUpdated( collectionUpdates, tables ) ||
327339
areTablesToUpdated( collectionCreations, tables ) ||
340+
areTablesToUpdated( collectionQueuedOps, tables ) ||
328341
areTablesToUpdated( collectionRemovals, tables );
329342
}
330343

@@ -401,6 +414,7 @@ public String toString() {
401414
.append( " collectionCreations=" ).append( collectionCreations )
402415
.append( " collectionRemovals=" ).append( collectionRemovals )
403416
.append( " collectionUpdates=" ).append( collectionUpdates )
417+
.append( " collectionQueuedOps=" ).append( collectionQueuedOps )
404418
.append( " unresolvedInsertDependencies=" ).append( unresolvedInsertions )
405419
.append( "]" )
406420
.toString();
@@ -436,6 +450,7 @@ public void sortCollectionActions() {
436450
//sort the updates by fk
437451
java.util.Collections.sort( collectionCreations );
438452
java.util.Collections.sort( collectionUpdates );
453+
java.util.Collections.sort( collectionQueuedOps );
439454
java.util.Collections.sort( collectionRemovals );
440455
}
441456
}
@@ -472,6 +487,7 @@ public ArrayList cloneDeletions() {
472487
public void clearFromFlushNeededCheck(int previousCollectionRemovalSize) {
473488
collectionCreations.clear();
474489
collectionUpdates.clear();
490+
collectionQueuedOps.clear();
475491
updates.clear();
476492
// collection deletions are a special case since update() can add
477493
// deletions of collections not loaded by the session.
@@ -495,6 +511,7 @@ public boolean hasAnyQueuedActions() {
495511
! unresolvedInsertions.isEmpty() ||
496512
deletions.size() > 0 ||
497513
collectionUpdates.size() > 0 ||
514+
collectionQueuedOps.size() > 0 ||
498515
collectionRemovals.size() > 0 ||
499516
collectionCreations.size() > 0;
500517
}
@@ -564,6 +581,13 @@ public void serialize(ObjectOutputStream oos) throws IOException {
564581
for ( int i = 0; i < queueSize; i++ ) {
565582
oos.writeObject( collectionCreations.get( i ) );
566583
}
584+
585+
queueSize = collectionQueuedOps.size();
586+
LOG.tracev( "Starting serialization of [{0}] collectionQueuedOps entries", queueSize );
587+
oos.writeInt( queueSize );
588+
for ( int i = 0; i < queueSize; i++ ) {
589+
oos.writeObject( collectionQueuedOps.get( i ) );
590+
}
567591
}
568592

569593
/**
@@ -640,6 +664,15 @@ public static ActionQueue deserialize(
640664
action.afterDeserialize( session );
641665
rtn.collectionCreations.add( action );
642666
}
667+
668+
queueSize = ois.readInt();
669+
LOG.tracev( "Starting deserialization of [{0}] collectionQueuedOps entries", queueSize );
670+
rtn.collectionQueuedOps = new ArrayList<Executable>( queueSize );
671+
for ( int i = 0; i < queueSize; i++ ) {
672+
CollectionAction action = ( CollectionAction ) ois.readObject();
673+
action.afterDeserialize( session );
674+
rtn.collectionQueuedOps.add( action );
675+
}
643676
return rtn;
644677
}
645678

hibernate-core/src/main/java/org/hibernate/event/internal/AbstractFlushingEventListener.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.hibernate.action.internal.CollectionRecreateAction;
3333
import org.hibernate.action.internal.CollectionRemoveAction;
3434
import org.hibernate.action.internal.CollectionUpdateAction;
35+
import org.hibernate.action.internal.QueuedOperationCollectionAction;
3536
import org.hibernate.collection.spi.PersistentCollection;
3637
import org.hibernate.engine.internal.Cascade;
3738
import org.hibernate.engine.internal.Collections;
@@ -293,6 +294,16 @@ private void flushCollections(final EventSource session, final PersistenceContex
293294
)
294295
);
295296
}
297+
if ( !coll.wasInitialized() && coll.hasQueuedOperations() ) {
298+
actionQueue.addAction(
299+
new QueuedOperationCollectionAction(
300+
coll,
301+
ce.getLoadedPersister(),
302+
ce.getLoadedKey(),
303+
session
304+
)
305+
);
306+
}
296307

297308
}
298309

hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1631,6 +1631,16 @@ public void updateRows(PersistentCollection collection, Serializable id, Session
16311631

16321632
protected abstract int doUpdateRows(Serializable key, PersistentCollection collection, SessionImplementor session)
16331633
throws HibernateException;
1634+
1635+
public void processQueuedOps(PersistentCollection collection, Serializable key, SessionImplementor session)
1636+
throws HibernateException {
1637+
if ( collection.hasQueuedOperations() ) {
1638+
doProcessQueuedOps( collection, key, session );
1639+
}
1640+
}
1641+
1642+
protected abstract void doProcessQueuedOps(PersistentCollection collection, Serializable key, SessionImplementor session)
1643+
throws HibernateException;
16341644

16351645
public CollectionMetadata getCollectionMetadata() {
16361646
return this;

hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,12 @@ else if ( hasIndex && !indexContainsFormula ) {
152152

153153
return update.toStatementString();
154154
}
155+
156+
@Override
157+
protected void doProcessQueuedOps(PersistentCollection collection, Serializable id, SessionImplementor session)
158+
throws HibernateException {
159+
// nothing to do
160+
}
155161

156162
/**
157163
* Generate the SQL DELETE that deletes a particular row

hibernate-core/src/main/java/org/hibernate/persister/collection/CollectionPersister.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,16 @@ public void insertRows(
198198
Serializable key,
199199
SessionImplementor session)
200200
throws HibernateException;
201+
202+
/**
203+
* Process queued operations within the PersistentCollection.
204+
*/
205+
public void processQueuedOps(
206+
PersistentCollection collection,
207+
Serializable key,
208+
SessionImplementor session)
209+
throws HibernateException;
210+
201211
/**
202212
* Get the name of this collection role (the fully qualified class name,
203213
* extended by a "property path")

hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -181,21 +181,26 @@ protected String generateDeleteRowString() {
181181
public void recreate(PersistentCollection collection, Serializable id, SessionImplementor session)
182182
throws HibernateException {
183183
super.recreate( collection, id, session );
184-
writeIndex( collection, id, session );
184+
writeIndex( collection, collection.entries( this ), id, session );
185185
}
186186

187187
@Override
188188
public void insertRows(PersistentCollection collection, Serializable id, SessionImplementor session)
189189
throws HibernateException {
190190
super.insertRows( collection, id, session );
191-
writeIndex( collection, id, session );
191+
writeIndex( collection, collection.entries( this ), id, session );
192192
}
193193

194-
private void writeIndex(PersistentCollection collection, Serializable id, SessionImplementor session) {
194+
@Override
195+
protected void doProcessQueuedOps(PersistentCollection collection, Serializable id, SessionImplementor session)
196+
throws HibernateException {
197+
writeIndex( collection, collection.queuedAdditionIterator(), id, session );
198+
}
199+
200+
private void writeIndex(PersistentCollection collection, Iterator entries, Serializable id, SessionImplementor session) {
195201
// If one-to-many and inverse, still need to create the index. See HHH-5732.
196202
if ( isInverse && hasIndex && !indexContainsFormula ) {
197203
try {
198-
Iterator entries = collection.entries( this );
199204
if ( entries.hasNext() ) {
200205
Expectation expectation = Expectations.appropriateExpectation( getUpdateCheckStyle() );
201206
int i = 0;
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package org.hibernate.test.annotations.onetomany;
2+
3+
import javax.persistence.Column;
4+
import javax.persistence.DiscriminatorColumn;
5+
import javax.persistence.DiscriminatorType;
6+
import javax.persistence.DiscriminatorValue;
7+
import javax.persistence.Entity;
8+
import javax.persistence.FetchType;
9+
import javax.persistence.GeneratedValue;
10+
import javax.persistence.GenerationType;
11+
import javax.persistence.Id;
12+
import javax.persistence.Inheritance;
13+
import javax.persistence.InheritanceType;
14+
import javax.persistence.JoinColumn;
15+
import javax.persistence.ManyToOne;
16+
17+
@Entity(name="Comment")
18+
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
19+
@DiscriminatorColumn(name = "DTYPE", discriminatorType= DiscriminatorType.STRING, length = 3)
20+
@DiscriminatorValue(value = "WPT")
21+
public class Comment {
22+
23+
private Long id;
24+
private Post post;
25+
private String name;
26+
private Forum forum;
27+
28+
@Id
29+
@GeneratedValue(strategy = GenerationType.AUTO)
30+
@Column(name = "id", updatable = false, insertable = false)
31+
public Long getId() {
32+
return id;
33+
}
34+
35+
public void setId(Long id) {
36+
this.id = id;
37+
}
38+
39+
@ManyToOne(optional=true,fetch=FetchType.LAZY)
40+
@JoinColumn(name="FK_PostId", nullable=true, insertable=true,updatable=false)
41+
public Post getPost() {
42+
return post;
43+
}
44+
45+
public void setPost(Post family) {
46+
this.post = family;
47+
}
48+
49+
@ManyToOne(optional=true,fetch=FetchType.LAZY)
50+
@JoinColumn(name="FK_ForumId", nullable=true, insertable=true,updatable=false)
51+
public Forum getForum() {
52+
return forum;
53+
}
54+
55+
public void setForum(Forum forum) {
56+
this.forum = forum;
57+
}
58+
59+
@Column
60+
public String getName() {
61+
return name;
62+
}
63+
64+
public void setName(String name) {
65+
this.name = name;
66+
}
67+
}

0 commit comments

Comments
 (0)