|
61 | 61 | use function array_sum; |
62 | 62 | use function array_values; |
63 | 63 | use function assert; |
| 64 | +use function count; |
64 | 65 | use function current; |
65 | 66 | use function get_debug_type; |
66 | 67 | use function implode; |
@@ -1039,28 +1040,60 @@ private function executeInserts(): void |
1039 | 1040 | { |
1040 | 1041 | $entities = $this->computeInsertExecutionOrder(); |
1041 | 1042 | $eventsToDispatch = []; |
| 1043 | + // @TODO #11977 this is ugly and to be tested: making it work, then refactoring later. |
| 1044 | + // We assemble micro-batches to process together: this should probably occur in a `private` function? |
| 1045 | + // @TODO #11977 test this by verifying the number of executed SQL queries in a flush operation? |
| 1046 | + // @TODO #11977 could this be applied also to batch updates? If so, let's raise a new issue. |
| 1047 | + /** @var list<array{class: Mapping\ClassMetadata, entities: non-empty-list<object>}> $batchedByType */ |
| 1048 | + $batchedByType = []; |
1042 | 1049 |
|
1043 | 1050 | foreach ($entities as $entity) { |
1044 | | - $oid = spl_object_id($entity); |
1045 | | - $class = $this->em->getClassMetadata($entity::class); |
| 1051 | + $currentClass = ($batchedByType[count($batchedByType) - 1]['class'] ?? null)?->getName(); |
| 1052 | + $entityClass = $this->em->getClassMetadata($entity::class); |
| 1053 | + |
| 1054 | + if ( |
| 1055 | + $currentClass !== $entityClass->name |
| 1056 | + // don't batch things together, if an ID generator is needed |
| 1057 | + || $entityClass->idGenerator->isPostInsertGenerator() |
| 1058 | + ) { |
| 1059 | + $batchedByType[] = [ |
| 1060 | + 'class' => $entityClass, |
| 1061 | + 'entities' => [$entity], |
| 1062 | + ]; |
| 1063 | + |
| 1064 | + continue; |
| 1065 | + } |
| 1066 | + |
| 1067 | + $batchedByType[count($batchedByType) - 1]['entities'][] = $entity; |
| 1068 | + } |
| 1069 | + |
| 1070 | + foreach ($batchedByType as $batch) { |
| 1071 | + $class = $batch['class']; |
| 1072 | + $invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::postPersist); |
1046 | 1073 | $persister = $this->getEntityPersister($class->name); |
1047 | 1074 |
|
1048 | | - $persister->addInsert($entity); |
| 1075 | + foreach ($batch['entities'] as $entity) { |
| 1076 | + $oid = spl_object_id($entity); |
| 1077 | + |
| 1078 | + $persister->addInsert($entity); |
1049 | 1079 |
|
1050 | | - unset($this->entityInsertions[$oid]); |
| 1080 | + unset($this->entityInsertions[$oid]); |
| 1081 | + } |
1051 | 1082 |
|
1052 | 1083 | $persister->executeInserts(); |
1053 | 1084 |
|
1054 | | - if (! isset($this->entityIdentifiers[$oid])) { |
1055 | | - //entity was not added to identity map because some identifiers are foreign keys to new entities. |
1056 | | - //add it now |
1057 | | - $this->addToEntityIdentifiersAndEntityMap($class, $oid, $entity); |
1058 | | - } |
| 1085 | + foreach ($batch['entities'] as $entity) { |
| 1086 | + $oid = spl_object_id($entity); |
1059 | 1087 |
|
1060 | | - $invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::postPersist); |
| 1088 | + if (! isset($this->entityIdentifiers[$oid])) { |
| 1089 | + //entity was not added to identity map because some identifiers are foreign keys to new entities. |
| 1090 | + //add it now |
| 1091 | + $this->addToEntityIdentifiersAndEntityMap($class, $oid, $entity); |
| 1092 | + } |
1061 | 1093 |
|
1062 | | - if ($invoke !== ListenersInvoker::INVOKE_NONE) { |
1063 | | - $eventsToDispatch[] = ['class' => $class, 'entity' => $entity, 'invoke' => $invoke]; |
| 1094 | + if ($invoke !== ListenersInvoker::INVOKE_NONE) { |
| 1095 | + $eventsToDispatch[] = ['class' => $class, 'entity' => $entity, 'invoke' => $invoke]; |
| 1096 | + } |
1064 | 1097 | } |
1065 | 1098 | } |
1066 | 1099 |
|
|
0 commit comments