doctrine实体管理器重复插入更新

时间:2016-10-25 08:37:13

标签: php mysql doctrine-orm doctrine symfony-3.1

我使用Symfony完整堆栈构建了一个处理XLSX文件的cli应用程序。但是,更新数据库记录中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();

实体类

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();是单身人士吗?

1 个答案:

答案 0 :(得分:1)

是的,默认情况下,symfony2服务的工作方式与singleton类似,您可以阅读:

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

  

了解范围¶

     

服务范围控制服务实例的时长   容器使用的。 Dependency Injection组件提供了两个   通用范围:

     

container(默认值):每次使用相同的实例   从这个容器请求它。 prototype:创建一个新实例   每次您请求服务

首先,如果你的'file'实体是从entityManager加载的,你就不能使用persist方法。 在刷新之前第二个转储'文件'实体并检查您尝试保存的内容。 您还可以在UnitOfWork上检查实体状态示例:

$unitOfWork = $entityManager->getUnitOfWork();

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

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

应用于实体X的持久操作的语义如下   如下:

     

如果X是一个新实体,它就会被管理。将输入实体X.   作为刷新操作的结果进入数据库。如果X是   预先存在的托管实体,由persist操作忽略。   但是,持久化操作会级联到引用的实体   X,如果映射了从X到这些其他实体的关系   cascade = PERSIST或cascade = ALL(参见“传递持久性”)。如果X是   一个被删除的实体,它就会被管理。如果X是一个分离的实体,那么   在flush上会抛出异常。

我以为你是在课堂上映射实体,但你不是,我无法理解你使用'DetectedType'的关系。 如果您在某处调用'clear'方法或者如果您对关系拥有方存在问题,则可能会出现此问题,请阅读以下内容:

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