学说实体管理器重复插入更新
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' 方法或者您对关系拥有方有疑问,可能会发生此问题,请阅读:
我已经使用 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' 方法或者您对关系拥有方有疑问,可能会发生此问题,请阅读: