|
21 | 21 | import org.hibernate.AssertionFailure; |
22 | 22 | import org.hibernate.HibernateException; |
23 | 23 | import org.hibernate.PropertyValueException; |
| 24 | +import org.hibernate.TransientObjectException; |
| 25 | +import org.hibernate.action.internal.AbstractEntityInsertAction; |
24 | 26 | import org.hibernate.action.internal.BulkOperationCleanupAction; |
25 | 27 | import org.hibernate.action.internal.EntityDeleteAction; |
26 | 28 | import org.hibernate.action.internal.UnresolvedEntityInsertActions; |
27 | 29 | import org.hibernate.action.spi.AfterTransactionCompletionProcess; |
28 | 30 | import org.hibernate.action.spi.BeforeTransactionCompletionProcess; |
29 | 31 | import org.hibernate.action.spi.Executable; |
30 | 32 | import org.hibernate.cache.CacheException; |
| 33 | +import org.hibernate.engine.internal.NonNullableTransientDependencies; |
31 | 34 | import org.hibernate.engine.spi.ActionQueue; |
32 | 35 | import org.hibernate.engine.spi.ComparableExecutable; |
33 | 36 | import org.hibernate.engine.spi.EntityEntry; |
34 | 37 | import org.hibernate.engine.spi.ExecutableList; |
35 | 38 | import org.hibernate.engine.spi.SessionFactoryImplementor; |
36 | 39 | import org.hibernate.engine.spi.SharedSessionContractImplementor; |
37 | | -import org.hibernate.metadata.ClassMetadata; |
38 | 40 | import org.hibernate.metamodel.spi.MappingMetamodelImplementor; |
39 | 41 | import org.hibernate.proxy.HibernateProxy; |
40 | 42 | import org.hibernate.proxy.LazyInitializer; |
|
59 | 61 |
|
60 | 62 | import static java.lang.invoke.MethodHandles.lookup; |
61 | 63 | import static org.hibernate.reactive.logging.impl.LoggerFactory.make; |
62 | | -import static org.hibernate.reactive.util.impl.CompletionStages.failedFuture; |
63 | 64 | import static org.hibernate.reactive.util.impl.CompletionStages.loop; |
64 | 65 | import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture; |
65 | 66 |
|
@@ -520,11 +521,21 @@ public CompletionStage<Void> executeInserts() { |
520 | 521 | */ |
521 | 522 | public CompletionStage<Void> executeActions() { |
522 | 523 | if ( hasUnresolvedEntityInsertActions() ) { |
523 | | - return failedFuture( new IllegalStateException( "About to execute actions, but there are unresolved entity insert actions." ) ); |
| 524 | + final AbstractEntityInsertAction insertAction = unresolvedInsertions |
| 525 | + .getDependentEntityInsertActions() |
| 526 | + .iterator() |
| 527 | + .next(); |
| 528 | + final NonNullableTransientDependencies transientEntities = insertAction.findNonNullableTransientEntities(); |
| 529 | + final Object transientEntity = transientEntities.getNonNullableTransientEntities().iterator().next(); |
| 530 | + final String path = transientEntities.getNonNullableTransientPropertyPaths(transientEntity).iterator().next(); |
| 531 | + //TODO: should be TransientPropertyValueException |
| 532 | + throw new TransientObjectException( "Persistent instance of '" + insertAction.getEntityName() |
| 533 | + + "' with id '" + insertAction.getId() |
| 534 | + + "' references an unsaved transient instance via attribute '" + path |
| 535 | + + "' (save the transient instance before flushing)" ); |
524 | 536 | } |
525 | 537 |
|
526 | 538 | CompletionStage<Void> ret = voidFuture(); |
527 | | - |
528 | 539 | for ( OrderedActions action : ORDERED_OPERATIONS ) { |
529 | 540 | ret = ret.thenCompose( v -> executeActions( action.getActions( this ) ) ); |
530 | 541 | } |
@@ -738,26 +749,6 @@ public int numberOfInsertions() { |
738 | 749 | return insertions.size(); |
739 | 750 | } |
740 | 751 |
|
741 | | -// public TransactionCompletionProcesses getTransactionCompletionProcesses() { |
742 | | -// return new TransactionCompletionProcesses( beforeTransactionProcesses(), afterTransactionProcesses() ); |
743 | | -// } |
744 | | -// |
745 | | -// /** |
746 | | -// * Bind transaction completion processes to make them shared between primary and secondary session. |
747 | | -// * Transaction completion processes are always executed by transaction owner (primary session), |
748 | | -// * but can be registered using secondary session too. |
749 | | -// * |
750 | | -// * @param processes Transaction completion processes. |
751 | | -// * @param isTransactionCoordinatorShared Flag indicating shared transaction context. |
752 | | -// */ |
753 | | -// public void setTransactionCompletionProcesses( |
754 | | -// TransactionCompletionProcesses processes, |
755 | | -// boolean isTransactionCoordinatorShared) { |
756 | | -// this.isTransactionCoordinatorShared = isTransactionCoordinatorShared; |
757 | | -// this.beforeTransactionProcesses = processes.beforeTransactionCompletionProcesses; |
758 | | -// this.afterTransactionProcesses = processes.afterTransactionCompletionProcesses; |
759 | | -// } |
760 | | - |
761 | 752 | public void sortCollectionActions() { |
762 | 753 | if ( isOrderUpdatesEnabled() ) { |
763 | 754 | // sort the updates by fk |
@@ -864,32 +855,6 @@ public void unScheduleDeletion(EntityEntry entry, Object rescuedEntity) { |
864 | 855 | throw new AssertionFailure( "Unable to perform un-delete for instance " + entry.getEntityName() ); |
865 | 856 | } |
866 | 857 |
|
867 | | -// /** |
868 | | -// * Used by the owning session to explicitly control serialization of the action queue |
869 | | -// * |
870 | | -// * @param oos The stream to which the action queue should get written |
871 | | -// * |
872 | | -// * @throws IOException Indicates an error writing to the stream |
873 | | -// */ |
874 | | -// public void serialize(ObjectOutputStream oos) throws IOException { |
875 | | -// LOG.trace( "Serializing action-queue" ); |
876 | | -// if ( unresolvedInsertions == null ) { |
877 | | -// unresolvedInsertions = new UnresolvedEntityInsertActions(); |
878 | | -// } |
879 | | -// unresolvedInsertions.serialize( oos ); |
880 | | -// |
881 | | -// for ( ListProvider<?> p : EXECUTABLE_LISTS_MAP.values() ) { |
882 | | -// ExecutableList<?> l = p.get( this ); |
883 | | -// if ( l == null ) { |
884 | | -// oos.writeBoolean( false ); |
885 | | -// } |
886 | | -// else { |
887 | | -// oos.writeBoolean( true ); |
888 | | -// l.writeExternal( oos ); |
889 | | -// } |
890 | | -// } |
891 | | -// } |
892 | | - |
893 | 858 | private abstract static class AbstractTransactionCompletionProcessQueue<T,U> { |
894 | 859 | final ReactiveSession session; |
895 | 860 |
|
@@ -994,21 +959,6 @@ public CompletionStage<Void> afterTransactionCompletion(boolean success) { |
994 | 959 | } |
995 | 960 | } |
996 | 961 |
|
997 | | -// /** |
998 | | -// * Wrapper class allowing to bind the same transaction completion process queues in different sessions. |
999 | | -// */ |
1000 | | -// public static class TransactionCompletionProcesses { |
1001 | | -// private final BeforeTransactionCompletionProcessQueue beforeTransactionCompletionProcesses; |
1002 | | -// private final AfterTransactionCompletionProcessQueue afterTransactionCompletionProcesses; |
1003 | | -// |
1004 | | -// private TransactionCompletionProcesses( |
1005 | | -// BeforeTransactionCompletionProcessQueue beforeTransactionCompletionProcessQueue, |
1006 | | -// AfterTransactionCompletionProcessQueue afterTransactionCompletionProcessQueue) { |
1007 | | -// this.beforeTransactionCompletionProcesses = beforeTransactionCompletionProcessQueue; |
1008 | | -// this.afterTransactionCompletionProcesses = afterTransactionCompletionProcessQueue; |
1009 | | -// } |
1010 | | -// } |
1011 | | - |
1012 | 962 | /** |
1013 | 963 | * Order the {@link #insertions} queue such that we group inserts against the same entity together (without |
1014 | 964 | * violating constraints). The original order is generated by cascade order, which in turn is based on the |
@@ -1152,26 +1102,23 @@ public void sort(List<ReactiveEntityInsertActionHolder> insertions) { |
1152 | 1102 | */ |
1153 | 1103 | private void addParentChildEntityNames(ReactiveEntityInsertAction action, BatchIdentifier batchIdentifier) { |
1154 | 1104 | Object[] propertyValues = action.getState(); |
1155 | | - ClassMetadata classMetadata = action.getPersister().getClassMetadata(); |
1156 | | - if ( classMetadata != null ) { |
1157 | | - Type[] propertyTypes = classMetadata.getPropertyTypes(); |
1158 | | - Type identifierType = classMetadata.getIdentifierType(); |
1159 | | - |
1160 | | - for ( int i = 0; i < propertyValues.length; i++ ) { |
1161 | | - Object value = propertyValues[i]; |
1162 | | - if (value!=null) { |
1163 | | - Type type = propertyTypes[i]; |
1164 | | - addParentChildEntityNameByPropertyAndValue( action, batchIdentifier, type, value ); |
1165 | | - } |
| 1105 | + Type[] propertyTypes = action.getPersister().getPropertyTypes(); |
| 1106 | + Type identifierType = action.getPersister().getIdentifierType(); |
| 1107 | + |
| 1108 | + for ( int i = 0; i < propertyValues.length; i++ ) { |
| 1109 | + Object value = propertyValues[i]; |
| 1110 | + if (value!=null) { |
| 1111 | + Type type = propertyTypes[i]; |
| 1112 | + addParentChildEntityNameByPropertyAndValue( action, batchIdentifier, type, value ); |
1166 | 1113 | } |
| 1114 | + } |
1167 | 1115 |
|
1168 | | - if ( identifierType.isComponentType() ) { |
1169 | | - CompositeType compositeType = (CompositeType) identifierType; |
1170 | | - Type[] compositeIdentifierTypes = compositeType.getSubtypes(); |
| 1116 | + if ( identifierType.isComponentType() ) { |
| 1117 | + CompositeType compositeType = (CompositeType) identifierType; |
| 1118 | + Type[] compositeIdentifierTypes = compositeType.getSubtypes(); |
1171 | 1119 |
|
1172 | | - for ( Type type : compositeIdentifierTypes ) { |
1173 | | - addParentChildEntityNameByPropertyAndValue( action, batchIdentifier, type, null ); |
1174 | | - } |
| 1120 | + for ( Type type : compositeIdentifierTypes ) { |
| 1121 | + addParentChildEntityNameByPropertyAndValue( action, batchIdentifier, type, null ); |
1175 | 1122 | } |
1176 | 1123 | } |
1177 | 1124 | } |
@@ -1275,10 +1222,9 @@ public boolean equals(Object o) { |
1275 | 1222 | if ( this == o ) { |
1276 | 1223 | return true; |
1277 | 1224 | } |
1278 | | - if ( !( o instanceof BatchIdentifier ) ) { |
| 1225 | + if ( !( o instanceof BatchIdentifier that ) ) { |
1279 | 1226 | return false; |
1280 | 1227 | } |
1281 | | - BatchIdentifier that = (BatchIdentifier) o; |
1282 | 1228 | return Objects.equals( entityName, that.entityName ); |
1283 | 1229 | } |
1284 | 1230 |
|
@@ -1315,9 +1261,7 @@ boolean hasAnyChildEntityNames(BatchIdentifier batchIdentifier) { |
1315 | 1261 | /** |
1316 | 1262 | * Check if this {@link BatchIdentifier} has a parent or grandparent |
1317 | 1263 | * matching the given {@link BatchIdentifier reference. |
1318 | | - * |
1319 | 1264 | * @param batchIdentifier {@link BatchIdentifier} reference |
1320 | | - * |
1321 | 1265 | * @return this {@link BatchIdentifier} has a parent matching the given {@link BatchIdentifier reference |
1322 | 1266 | */ |
1323 | 1267 | boolean hasParent(BatchIdentifier batchIdentifier) { |
|
0 commit comments