此处涉及三个实体:部署, declovementStep , declovermentStatusLog 。我将首先粘贴这些类的相关定义
src/my/bundle/entity/deployment.php
<?php
namespace MyBundleEntity;
use DoctrineORMMapping as ORM;
use DoctrineCommonCollectionsArrayCollection;
use DoctrineORMPersistentCollection;
/**
* @ORMTable(name="deployment")
* @ORMEntity()
*/
class Deployment
{
/**
* Status Log Entries for this deployment
*
* @var DoctrineORMPersistentCollection
*
* @ORMOneToMany(targetEntity="DeploymentStatusLog", mappedBy="deployment", cascade={"persist","remove"})
* @ORMOrderBy({"created_at"="DESC"})
*/
protected $status_logs;
/**
* @var DoctrineORMPersistentCollection
*
* @ORMOneToMany(targetEntity="DeploymentStep", mappedBy="deployment", cascade={"persist","remove"})
* @ORMOrderBy({"sequence" = "ASC"})
*/
protected $steps;
public function __construct()
{
$this->status_logs = new ArrayCollection();
$this->steps = new ArrayCollection();
}
/**
* Add status_logs
*
* @param DeploymentStatusLog $statusLogs
*/
public function addDeploymentStatusLog(DeploymentStatusLog $statusLogs)
{
$this->status_logs[] = $statusLogs;
}
/**
* Add steps
*
* @param DeploymentStep $steps
*/
public function addDeploymentStep(DeploymentStep $steps)
{
$this->steps[] = $steps;
}
// ...
}
src/my/bundle/entity/deploymentStep.php
<?php
namespace MyBundleEntity;
use DoctrineORMMapping as ORM;
/**
* @ORMTable(name="deployment_step")
* @ORMEntity()
*/
class DeploymentStep
{
/**
* @var Deployment
*
* @ORMManyToOne(targetEntity="Deployment", cascade={"all"})
* @ORMJoinColumn(name="deployment_id", referencedColumnName="id")
* @GedmoSortableGroup
*/
private $deployment;
/**
* Set deployment
*
* @param Deployment $deployment
*/
public function setDeployment(Deployment $deployment)
{
$this->deployment = $deployment;
}
// ...
}
src/my/bundle/entity/deploymentStatuslog.php
<?php
namespace MyBundleEntity;
use DoctrineORMMapping as ORM;
/**
* @ORMTable(name="deployment_status_log")
* @ORMEntity()
*/
class DeploymentStatusLog
{
/**
* @var Deployment
*
* @ORMManyToOne(targetEntity="Deployment", cascade={"all"})
* @ORMJoinColumn(name="deployment_id", referencedColumnName="id", nullable=false)
*/
protected $deployment;
/**
* Set deployment
*
* @param Deployment $deployment
*/
public function setDeployment( Deployment $deployment)
{
$this->deployment = $deployment;
}
// ...
}
现在,当我尝试一次为所有这三个实体创建全新记录时,就会出现问题。在控制器中:
$em = $this->getDoctrine()->getEntityManager();
$deployment = new Deployment();
$form = $this->createForm(new DeploymentType($em), $deployment);
if ($request->getMethod() == 'POST')
{
$form->bindRequest($request);
if ($form->isValid())
{
$codeStep = new DeploymentStep();
$codeStep->setDeployment( $deployment );
// Other setters on DeploymentStep
$deploymentStatusLog = new DeploymentStatusLog();
$deploymentStatusLog->setDeployment( $deployment );
// Other setters on DeploymentStatusLog
$deployment->addDeploymentStep( $codeStep );
$deployment->addDeploymentStatusLog( $deploymentStatusLog );
$em->persist( $deployment );
$em->flush();
}
}
单位工程处理时会发生什么,它会抛出一个怪异的异常,抱怨不确定的索引:
异常" errorexception"带有消息'注意:未定义的索引: 000000001294F82200000000006B6F9F2C IN /project/vendor/doctrine/lib/doctrine/orm/unitofwork.php line 2252'in /project/vendor/symfony/src/symfony/component/httpkernel/debug/erorhandler.php:67
现在,如果我坚持/刷新部署 Entity,然后然后 persist/plassist/flush the关联,它将成功。
因此,虽然i can 这样做是为了使应用程序的这一部分起作用,但感觉有点错误,因为这个过程应该是原子,而且这就是全部要点从。
开始的交易查询有线索?
- Symfony 2.0.15
- 学说2.1.7
- php 5.3.3
- mysql 5.1.52
- Apache 2.2.15
编辑
通过请求的完整堆栈跟踪
exception 'ErrorException' with message 'Notice: Undefined index: 000000004081f5f9000000005f1dbbfc in /project/vendor/doctrine/lib/Doctrine/ORM/UnitOfWork.php line 2252' in /project/vendor/symfony/src/Symfony/Component/HttpKernel/Debug/ErrorHandler.php:67
Stack trace:
#0 /project/vendor/doctrine/lib/Doctrine/ORM/UnitOfWork.php(2252): SymfonyComponentHttpKernelDebugErrorHandler->handle(8, 'Undefined index...', '/mnt/hgfs/mount...', 2252, Array)
#1 /project/vendor/doctrine/lib/Doctrine/ORM/Query.php(321): DoctrineORMUnitOfWork->getEntityIdentifier(Object(MyBundleEntityDeployment))
#2 /project/vendor/doctrine/lib/Doctrine/ORM/Query.php(274): DoctrineORMQuery->processParameterValue(Object(MyBundleEntityDeployment))
#3 /project/vendor/doctrine/lib/Doctrine/ORM/Query.php(243): DoctrineORMQuery->processParameterMappings(Array)
#4 /project/vendor/doctrine/lib/Doctrine/ORM/AbstractQuery.php(607): DoctrineORMQuery->_doExecute()
#5 /project/vendor/doctrine/lib/Doctrine/ORM/AbstractQuery.php(413): DoctrineORMAbstractQuery->execute(Array, 1)
#6 /project/vendor/gedmo-doctrine-extensions/lib/Gedmo/Sortable/SortableListener.php(344): DoctrineORMAbstractQuery->getResult()
#7 /project/vendor/gedmo-doctrine-extensions/lib/Gedmo/Sortable/SortableListener.php(133): GedmoSortableSortableListener->getMaxPosition(Object(DoctrineORMEntityManager), Object(DoctrineORMMappingClassMetadata), Array, Object(MyBundleEntityDeploymentStep))
#8 /project/vendor/gedmo-doctrine-extensions/lib/Gedmo/Sortable/SortableListener.php(100): GedmoSortableSortableListener->processInsert(Object(DoctrineORMEntityManager), Array, Object(DoctrineORMMappingClassMetadata), Object(MyBundleEntityDeploymentStep))
#9 /project/vendor/doctrine-common/lib/Doctrine/Common/EventManager.php(64): GedmoSortableSortableListener->onFlush(Object(DoctrineORMEventOnFlushEventArgs))
#10 /project/vendor/doctrine/lib/Doctrine/ORM/UnitOfWork.php(280): DoctrineCommonEventManager->dispatchEvent('onFlush', Object(DoctrineORMEventOnFlushEventArgs))
#11 /project/vendor/doctrine/lib/Doctrine/ORM/EntityManager.php(334): DoctrineORMUnitOfWork->commit()
#12 /project/src/My/Bundle/Controller/DeploymentController.php(214): DoctrineORMEntityManager->flush()
#13 [internal function]: MyBundleControllerDeploymentController->createAction(Object(MyBundleEntityRelease), Object(SymfonyComponentHttpFoundationRequest))
#14 /project/vendor/bundles/JMS/SecurityExtraBundle/Security/Authorization/Interception/MethodSecurityInterceptor.php(73): ReflectionMethod->invokeArgs(Object(MyBundleControllerDeploymentController), Array)
#15 /project/app/cache/dev/classes.php(9391) : eval()'d code(1): JMSSecurityExtraBundleSecurityAuthorizationInterceptionMethodSecurityInterceptor->invoke(Object(JMSSecurityExtraBundleSecurityAuthorizationInterceptionMethodInvocation), Array)
#16 [internal function]: {closure}(Object(MyBundleEntityRelease), Object(SymfonyComponentHttpFoundationRequest))
#17 /project/app/cache/dev/classes.php(3925): call_user_func_array(Object(Closure), Array)
#18 /project/app/cache/dev/classes.php(3895): SymfonyComponentHttpKernelHttpKernel->handleRaw(Object(SymfonyComponentHttpFoundationRequest), 1)
#19 /project/app/cache/dev/classes.php(4899): SymfonyComponentHttpKernelHttpKernel->handle(Object(SymfonyComponentHttpFoundationRequest), 1, true)
#20 /project/app/bootstrap.php.cache(551): SymfonyBundleFrameworkBundleHttpKernel->handle(Object(SymfonyComponentHttpFoundationRequest), 1, true)
#21 /project/web/app_dev.php(18): SymfonyComponentHttpKernelKernel->handle(Object(SymfonyComponentHttpFoundationRequest))
#22 {main}
编辑2
根据要求的创建操作的完整代码
/**
* @Route("/create/{id}", name="deployment_create_id")
* @ParamConverter("release", class="MyBundle:Release")
* @Method({"POST","GET"})
* @Secure(roles="ROLE_DEPLOYMENT_PLANNER")
* @Template()
*/
public function createAction( Release $release, Request $request )
{
$em = $this->getDoctrine()->getEntityManager();
$sessionUser = $this->get('security.context')->getToken()->getUser();
$deployment = new Deployment();
$deployment->setRelease( $release );
$deployment->setAuthor( $sessionUser );
$form = $this->createForm(new DeploymentType($em), $deployment);
if ($request->getMethod() == 'POST')
{
$form->bindRequest($request);
if ($form->isValid())
{
$codeStep = new DeploymentStep();
$codeStep->setDeployment( $deployment );
$codeStep->setSequence( 0 );
$codeStep->setTitle( "Update Code" );
$codeStep->setDetails( "Update codebase per the plan's specifications" );
$codeStep->setDeploymentStepType(
$em->getRepository('MyBundle:DeploymentStepType')->findOneBy(
array( 'name' => DeploymentStepType::TYPE_OTHER )
)
);
$deploymentStatusLog = new DeploymentStatusLog();
$deploymentStatusLog->setDeployment( $deployment );
$deploymentStatusLog->setUser( $sessionUser );
$deploymentStatusLog->setNotes( 'New Deployment Created' );
$deploymentStatusLog->setDeploymentStatus(
$em->getRepository('MyBundle:DeploymentStatus')->findOneBy(
array( 'title' => DeploymentStatus::STATUS_NEW )
)
);
$deployment->addDeploymentStep( $codeStep );
$deployment->addDeploymentStatusLog( $deploymentStatusLog );
try {
$em->persist( $deployment );
$em->persist( $codeStep );
$em->persist( $deploymentStatusLog );
$em->flush();
return $this->redirectSuccess(
'Deployment created.'
, $release->getRouteName()
, $release->getRouteParameters()
);
}
catch ( Exception $e )
{
$this->setFlashErrorMessage( 'Error saving deployment.' );
}
}
}
return array(
'release' => $release
, 'form' => $form->createView()
);
}
我也有同样的问题,就我而言,这是因为我正在做一个实体remove
&amp;flush
在postRemove
生命周期事件中。从我可以在单位工程逻辑中掌握的东西,您不能在那个事件中调用Flush。这样做将冲洗所有仍在悬而未决的动作,从第一次打电话给Flush,这将被事件的冲洗电话删除。弄清楚了这一点之后,我能够找到证实我的怀疑的学说手册的这一部分:
http://docs.doctrine-project.org/en/latest/reference/events.html#postupdate-postremove-postpersist
您可以正确地假设单独冲洗每个步骤是一种不好的方法,但是如果您不使用生命周期事件,那么我不确定是什么会导致您的特定问题。我能够通过在UnitOfWork.php
的executeDeletions
函数中记录对象ID变量($oid
)来调试问题。我注意到反复删除了同一ID,一旦从$this->entityIdentifiers
不设置,它将在随后的删除中失败。
我的解决方案是简单地在postRemove
事件中分类每个ID,然后实际上删除postFlush
事件中的实体,这不是生命周期事件,因此可以进行后续的持久操作:
http://docs.doctrine-project.org/en/latest/reference/events.html#lifecycle-ext
我确定您已经继续前进,但是如果其他人遇到这个问题...
这不是"解决方案",但我希望它为他人提供更多的故障排除。
我在遵循学说的批处理质量插入件的建议时也遇到了同样的错误。仅供参考,这是来自控制器(不是像其他答案那样的生命周期事件)。
学说的推荐方法
$batchSize = 20;
for ($i = 1; $i <= 10000; ++$i) {
$user = new CmsUser;
$user->setStatus('user');
$user->setUsername('user' . $i);
$user->setName('Mr.Smith-' . $i);
$em->persist($user);
if (($i % $batchSize) === 0) {
$em->flush();
$em->clear(); // Detaches all objects from Doctrine!
}
}
$em->flush(); //Persist objects that did not make up an entire batch
$em->clear();
当我使用与上面推荐的代码类似的东西时,它会在2000年插入大约2000插入后出现相同的错误。
更改持久的顺序
我坚持10,000个实体的顺序没有区别。如果我坚持,冲洗和清除每个循环(不是理想的,但我尝试过),那没有什么区别。
删除清除
如果我只是在$ batchsize支票中评论了$em->clear()
,并且只在循环完成后才清楚地表明它,那么它就计时了:
Fatal error: Maximum execution time of 30 seconds exceeded in /var/www/core/cms/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php on line 541
所以我在脚本上放了一个 set_time_limit(3600)
以防止时间,但它不再给出错误,但它耗尽了记忆:p
这表明当$em->clear()
在循环中执行时,问题发生。这与其他问题一致。不幸的是,如果没有$em->clear()
,您会很快用光记忆。
禁用事件听众
其他答案提到事件听众可能导致了这一点,所以我像建议的那样禁用了他们:
foreach ($em->getEventManager()->getListeners() as $event => $listeners) {
foreach ($listeners as $listener) {
$em->getEventManager()->removeEventListener($event, $listener);
}
}
但这也不起作用...尽管似乎这可能是问题,但实际上并没有成功地禁用它们。
验证模式
我还验证了我的模式:
php app/console doctrine:schema:validate
,没有报告任何错误。
[Mapping] OK - The mapping files are correct.
[Database] OK - The database schema is in sync with the mapping files.