lib/Doctrine/ORM/Persisters/Collection/OneToManyPersister.php
private function deleteJoinedEntityCollection(PersistentCollection $collection)
    {
        $association     = $collection->getMapping();
        $targetClass     = $this->em->getClassMetadata($association->getTargetEntity());
        $rootClass       = $this->em->getClassMetadata($targetClass->getRootClassName());
        $sourcePersister = $this->uow->getEntityPersister($association->getSourceEntity());

        // 1) Build temporary table DDL
        $tempTable         = $this->platform->getTemporaryTableName($rootClass->getTemporaryIdTableName());
        $idColumns         = $rootClass->getIdentifierColumns($this->em);
        $idColumnNameList  = implode(', ', array_keys($idColumns));
        $columnDefinitions = [];

        foreach ($idColumns as $columnName => $column) {
            $type = $column->getType();

            $columnDefinitions[$columnName] = [
                'notnull' => true,
                'type'    => $type,
            ];
        }

        $statement = $this->platform->getCreateTemporaryTableSnippetSQL() . ' ' . $tempTable
            . ' (' . $this->platform->getColumnDeclarationListSQL($columnDefinitions) . ')';

        $this->conn->executeUpdate($statement);

        // 2) Build insert table records into temporary table
        $dql   = ' SELECT t0.' . implode(', t0.', $rootClass->getIdentifierFieldNames())
               . ' FROM ' . $targetClass->getClassName() . ' t0 WHERE t0.' . $association->getMappedBy() . ' = :owner';
        $query = $this->em->createQuery($dql)->setParameter('owner', $collection->getOwner());

        $statement  = 'INSERT INTO ' . $tempTable . ' (' . $idColumnNameList . ') ' . $query->getSQL();
        $parameters = array_values($sourcePersister->getIdentifier($collection->getOwner()));
        $numDeleted = $this->conn->executeUpdate($statement, $parameters);

        // 3) Create statement used in DELETE ... WHERE ... IN (subselect)
        $deleteSQLTemplate = sprintf(
            'DELETE FROM %%s WHERE (%s) IN (SELECT %s FROM %s)',
            $idColumnNameList,
            $idColumnNameList,
            $tempTable
        );

        // 4) Delete records on each table in the hierarchy
        $hierarchyClasses = array_merge(
            array_map(
                function ($className) {
                    return $this->em->getClassMetadata($className);
                },
                array_reverse($targetClass->getSubClasses())
            ),
            [$targetClass],
            $targetClass->getAncestorsIterator()->getArrayCopy()
        );

        foreach ($hierarchyClasses as $class) {
            $statement = sprintf($deleteSQLTemplate, $class->table->getQuotedQualifiedName($this->platform));

            $this->conn->executeUpdate($statement);
        }

        // 5) Drop temporary table
        $statement = $this->platform->getDropTemporaryTableSQL($tempTable);

        $this->conn->executeUpdate($statement);

        return $numDeleted;
    }
private function deleteJoinedEntityCollection(PersistentCollection $collection)
    {
        $association     = $collection->getMapping();
        $targetClass     = $this->em->getClassMetadata($association->getTargetEntity());
        $rootClass       = $this->em->getClassMetadata($targetClass->getRootClassName());
        $sourcePersister = $this->uow->getEntityPersister($association->getSourceEntity());

        // 1) Build temporary table DDL
        $tempTable         = $this->platform->getTemporaryTableName($rootClass->getTemporaryIdTableName());
        $idColumns         = $rootClass->getIdentifierColumns($this->em);
        $idColumnNameList  = implode(', ', array_keys($idColumns));
        $columnDefinitions = [];

        foreach ($idColumns as $columnName => $column) {
            $type = $column->getType();

            $columnDefinitions[$columnName] = [
                'notnull' => true,
                'type'    => $type,
            ];
        }

        $statement = $this->platform->getCreateTemporaryTableSnippetSQL() . ' ' . $tempTable
            . ' (' . $this->platform->getColumnDeclarationListSQL($columnDefinitions) . ')';

        $this->conn->executeUpdate($statement);

        // 2) Build insert table records into temporary table
        $dql   = ' SELECT t0.' . implode(', t0.', $rootClass->getIdentifierFieldNames())
               . ' FROM ' . $targetClass->getClassName() . ' t0 WHERE t0.' . $association->getMappedBy() . ' = :owner';
        $query = $this->em->createQuery($dql)->setParameter('owner', $collection->getOwner());

        $statement  = 'INSERT INTO ' . $tempTable . ' (' . $idColumnNameList . ') ' . $query->getSQL();
        $parameters = array_values($sourcePersister->getIdentifier($collection->getOwner()));
        $numDeleted = $this->conn->executeUpdate($statement, $parameters);

        // 3) Create statement used in DELETE ... WHERE ... IN (subselect)
        $deleteSQLTemplate = sprintf(
            'DELETE FROM %%s WHERE (%s) IN (SELECT %s FROM %s)',
            $idColumnNameList,
            $idColumnNameList,
            $tempTable
        );

        // 4) Delete records on each table in the hierarchy
        $hierarchyClasses = array_merge(
            array_map(
                function ($className) {
                    return $this->em->getClassMetadata($className);
                },
                array_reverse($targetClass->getSubClasses())
            ),
            [$targetClass],
            $targetClass->getAncestorsIterator()->getArrayCopy()
        );

        foreach ($hierarchyClasses as $class) {
            $statement = sprintf($deleteSQLTemplate, $class->table->getQuotedQualifiedName($this->platform));

            $this->conn->executeUpdate($statement);
        }

        // 5) Drop temporary table
        $statement = $this->platform->getDropTemporaryTableSQL($tempTable);

        $this->conn->executeUpdate($statement);

        return $numDeleted;
    }
private function deleteJoinedEntityCollection ( PersistentCollection $ collection ) { $ association = $ collection -> getMapping ( ) ; $ targetClass = $ this -> em -> getClassMetadata ( $ association -> getTargetEntity ( ) ) ; $ rootClass = $ this -> em -> getClassMetadata ( $ targetClass -> getRootClassName ( ) ) ; $ sourcePersister = $ this -> uow -> getEntityPersister ( $ association -> getSourceEntity ( ) ) ; // 1) Build temporary table DDL $ tempTable = $ this -> platform -> getTemporaryTableName ( $ rootClass -> getTemporaryIdTableName ( ) ) ; $ idColumns = $ rootClass -> getIdentifierColumns ( $ this -> em ) ; $ idColumnNameList = implode ( ', ' , array_keys ( $ idColumns ) ) ; $ columnDefinitions = [ ] ; foreach ( $ idColumns as $ columnName => $ column ) { $ type = $ column -> getType ( ) ; $ columnDefinitions [ $ columnName ] = [ 'notnull' => true , 'type' => $ type , ] ; } $ statement = $ this -> platform -> getCreateTemporaryTableSnippetSQL ( ) . ' ' . $ tempTable . ' (' . $ this -> platform -> getColumnDeclarationListSQL ( $ columnDefinitions ) . ')' ; $ this -> conn -> executeUpdate ( $ statement ) ; // 2) Build insert table records into temporary table $ dql = ' SELECT t0.' . implode ( ', t0.' , $ rootClass -> getIdentifierFieldNames ( ) ) . ' FROM ' . $ targetClass -> getClassName ( ) . ' t0 WHERE t0.' . $ association -> getMappedBy ( ) . ' = :owner' ; $ query = $ this -> em -> createQuery ( $ dql ) -> setParameter ( 'owner' , $ collection -> getOwner ( ) ) ; $ statement = 'INSERT INTO ' . $ tempTable . ' (' . $ idColumnNameList . ') ' . $ query -> getSQL ( ) ; $ parameters = array_values ( $ sourcePersister -> getIdentifier ( $ collection -> getOwner ( ) ) ) ; $ numDeleted = $ this -> conn -> executeUpdate ( $ statement , $ parameters ) ; // 3) Create statement used in DELETE ... WHERE ... IN (subselect) $ deleteSQLTemplate = sprintf ( 'DELETE FROM %%s WHERE (%s) IN (SELECT %s FROM %s)' , $ idColumnNameList , $ idColumnNameList , $ tempTable ) ; // 4) Delete records on each table in the hierarchy $ hierarchyClasses = array_merge ( array_map ( function ( $ className ) { return $ this -> em -> getClassMetadata ( $ className ) ; } , array_reverse ( $ targetClass -> getSubClasses ( ) ) ) , [ $ targetClass ] , $ targetClass -> getAncestorsIterator ( ) -> getArrayCopy ( ) ) ; foreach ( $ hierarchyClasses as $ class ) { $ statement = sprintf ( $ deleteSQLTemplate , $ class -> table -> getQuotedQualifiedName ( $ this -> platform ) ) ; $ this -> conn -> executeUpdate ( $ statement ) ; } // 5) Drop temporary table $ statement = $ this -> platform -> getDropTemporaryTableSQL ( $ tempTable ) ; $ this -> conn -> executeUpdate ( $ statement ) ; return $ numDeleted ; }
Delete Class Table Inheritance entities.
A temporary table is needed to keep IDs to be deleted in both parent and child class' tables.

Thanks Steve Ebersole (Hibernate) for idea on how to tackle reliably this scenario, we owe him a beer! =)

@return int

@throws DBALException
Delete Class Table Inheritance entities . A temporary table is needed to keep IDs to be deleted in both parent and child class tables .