|
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