学说实体管理器重复插入更新

doctrine entity manager duplicate insert on update

我已经使用 Symfony 全栈构建了一个 cli 应用程序来处理 XLSX 文件。但是,在 2 个不同点更新数据库记录中的信息会导致记录被复制而不是更新。

应用程序最简单的细分是:

命令

class AppProcessFilesCommand extends ContainerAwareCommand
{

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $em = $this-setContainer>getContainer()->get('doctrine')->getManager();
        $file = $em->getRepository( 'AppBundle:FileToSync' )->findBy(
                ['processed' => null],
                ['modified' => 'ASC']
            );
            if (sizeof($file) > 0) {
                $file = $file[0];

                foreach (ProcessorFactory::getAvailableProcessors() as $processor) {
                    $start = microtime( true );                        
                    if (ProcessorFactory::getInstance( $processor )
                                        ->setOutput( $output )
                                        ->setContainer( $this->getContainer() )
                                        ->setDoctrine( $this->getContainer()->get( 'doctrine' ) )
                                        ->process( $file )
                    ) {
                        $processorFound = true;
                        $file->setTimeTaken( microtime( true ) - $start );
                        $file->setProcessed( new \DateTime() );
                        $em->persist($file);
                        $em->flush();
                    }
                }

处理循环

class Processor
{
    public function process($fileToSync)
    {
        $foundFiles = $this->convertToCsv($file);
        $noRows = $this->processCsvSheets($foundFiles, $fileToSync);

        $em = $this->getDoctrine()->getManager();
        $fileToSync->setDetectedTypeId($this->getMyFileTypeId());
        $fileToSync->setRowCount($noRows);
        $em->persist($fileToSync);
        $em->flush();

实体class

namespace AppBundle\Entity;


class FileToSync
{
    private $id;

    private $absolute_path;

    private $modified;

    private $processed;

    /**
     * @var int
     */
    private $detected_type_id;

    private $time_taken;

    private $row_count;

        /**
     * @var \AppBundle\Entity\DetectedType
     */
    private $DetectedType;


    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set absolutePath
     *
     * @param string $absolutePath
     *
     * @return FileToSync
     */
    public function setAbsolutePath($absolutePath)
    {
        $this->absolute_path = $absolutePath;

        return $this;
    }

    /**
     * Get absolutePath
     *
     * @return string
     */
    public function getAbsolutePath()
    {
        return $this->absolute_path;
    }

    /**
     * Set modified
     *
     * @param \DateTime $modified
     *
     * @return FileToSync
     */
    public function setModified($modified)
    {
        $this->modified = $modified;

        return $this;
    }

    /**
     * Get modified
     *
     * @return \DateTime
     */
    public function getModified()
    {
        return $this->modified;
    }

    /**
     * Set detectedTypeId
     *
     * @param \integer $detectedTypeId
     *
     * @return FileToSync
     */
    public function setDetectedTypeId($detectedTypeId)
    {
        $this->detected_type_id = $detectedTypeId;

        return $this;
    }

    /**
     * Get detectedTypeId
     *
     * @return \integer
     */
    public function getDetectedTypeId()
    {
        return $this->detected_type_id;
    }

    /**
     * Set processed
     *
     * @param \datetime $processed
     *
     * @return FileToSync
     */
    public function setProcessed(\datetime $processed)
    {
        $this->processed = $processed;

        return $this;
    }

    /**
     * Get processed
     *
     * @return \datetime
     */
    public function getProcessed()
    {
        return $this->processed;
    }

    /**
     * Set detectedType
     *
     * @param \AppBundle\Entity\DetectedType $detectedType
     *
     * @return FileToSync
     */
    public function setDetectedType(\AppBundle\Entity\DetectedType $detectedType = null)
    {
        $this->DetectedType = $detectedType;

        return $this;
    }

    /**
     * Get detectedType
     *
     * @return \AppBundle\Entity\DetectedType
     */
    public function getDetectedType()
    {
        return $this->DetectedType;
    }

    /**
     * Set timeTaken
     *
     * @param string $timeTaken
     *
     * @return FileToSync
     */
    public function setTimeTaken($timeTaken)
    {
        $this->time_taken = $timeTaken;

        return $this;
    }

    /**
     * Get timeTaken
     *
     * @return string
     */
    public function getTimeTaken()
    {
        return $this->time_taken;
    }

    /**
     * Set rowCount
     *
     * @param integer $rowCount
     *
     * @return FileToSync
     */
    public function setRowCount($rowCount)
    {
        $this->row_count = $rowCount;

        return $this;
    }

    /**
     * Get rowCount
     *
     * @return integer
     */
    public function getRowCount()
    {
        return $this->row_count;
    }
}

实体映射 (yml)

AppBundle\Entity\DetectedType:
    type: entity
    table: detected_type
    id:
        id:
            type: integer
            generator: { strategy: AUTO }
    fields:
        name:
            type: string
            length: 501

AppBundle\Entity\FileToSync:
    type: entity
    table: file_to_sync
    id:
        id:
            type: integer
            generator: { strategy: AUTO }
    manyToOne:
        DetectedType:
            targetEntity: DetectedType
            joinColumn:
                name: detected_type_id
                referencedColumnName: id
    fields:
        absolute_path:
            type: string
            length: 255
        modified:
            type: datetime
        detected_type_id:
            type: integer
            nullable: true
        processed:
            type: datetime
            nullable: true
        time_taken:
            type: decimal
            precision: 11
            scale: 6
            nullable: true
        row_count:
            type: integer
            nullable: true


AppBundle\Entity\Transaction:
    type: entity
    table: transaction
    id:
        id:
            type: integer
            generator: { strategy: AUTO }
    uniqueConstraints:
        txnId:
          columns: [ txn_id ]
    manyToOne:
        FileToSync:
            targetEntity: FileToSync
            joinColumn:
                name: file_id
                referencedColumnName: id
    fields:
        txnDate:
            type: datetime
        file_id:
            type: integer

在处理循环中,$fileToSync 没有更新,而是插入了一条新记录。然后在命令中更新。

我的工作假设是 $this->getContainer()->get('doctrine')->getManager();作为单身人士工作?

是的,默认情况下 symfony2 服务像单例一样工作,您可以阅读:

http://symfony.com/doc/2.6/cookbook/service_container/scopes.html

Understanding Scopes¶

The scope of a service controls how long an instance of a service is used by the container. The Dependency Injection component provides two generic scopes:

container (the default one): The same instance is used each time you request it from this container. prototype: A new instance is created each time you request the service

首先,如果您的 'file' 实体是从 entityManager 加载的,则不能使用持久化方法。 在刷新之前第二次转储 'file' 实体并检查您尝试保存的内容。 您也可以在 UnitOfWork 此处查看实体状态示例:

$unitOfWork = $entityManager->getUnitOfWork();

foreach ($unitOfWork->getScheduledEntityInsertions() as $entity) {
   #for insert
}

foreach ($unitOfWork->getScheduledEntityUpdates() as $entity) {
    # for update
}

The semantics of the persist operation, applied on an entity X, are as follows:

If X is a new entity, it becomes managed. The entity X will be entered into the database as a result of the flush operation. If X is a preexisting managed entity, it is ignored by the persist operation. However, the persist operation is cascaded to entities referenced by X, if the relationships from X to these other entities are mapped with cascade=PERSIST or cascade=ALL (see “Transitive Persistence”). If X is a removed entity, it becomes managed. If X is a detached entity, an exception will be thrown on flush.

我以为你在 class 中映射实体,但你不是,我无法理解你在 'DetectedType' 中使用的是哪种关系。 如果您在某处调用 'clear' 方法或者您对关系拥有方有疑问,可能会发生此问题,请阅读:

http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/unitofwork-associations.html