首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何判断当前事务是否会使用Doctrine 2更改任何实体?

如何判断当前事务是否会使用Doctrine 2更改任何实体?
EN

Stack Overflow用户
提问于 2013-03-07 20:58:44
回答 4查看 3.8K关注 0票数 5

我使用Doctrine来保存用户数据,我希望有一个last modification字段。下面是我希望在用户按下Save后保存表单的伪代码

  • 启动事务
  • 做很多事情,可能是查询数据库,可能不是
  • 如果有任何事情将被此事务更改
    • 修改last updated字段

  • 提交事务

有问题的部分是if anything will be changed by this transaction。理论能给我这样的信息吗?

如何判断实体在当前事务中是否发生了更改?

编辑

为了澄清问题,我试图在一个名为lastUpdated的实体中修改一个名为User的字段,前提是一旦currect事务完成,任何实体(包括但不限于User)都将被更改。换句话说,如果启动事务并修改名为nbCars的实体的Garage字段,则希望更新User实体的lastUpdated字段,即使该实体尚未被修改。

EN

回答 4

Stack Overflow用户

发布于 2013-03-13 00:00:29

这是一个必要的答复,目的是纠正@ColinMorelli发布的内容(因为不允许在生命周期事件侦听器中刷新--是的,文档中有一个位置不允许,但是我们会处理掉它,所以请不要这样做!)

您可以简单地使用侦听器收听onFlush,如下所示:

代码语言:javascript
复制
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\OnFlushEventArgs;
use Doctrine\ORM\Events;

class UpdateUserEventSubscriber implements EventSubscriber
{
    protected $user;

    public function __construct(User $user)
    {
        // assuming the user is managed here
        $this->user = $user;
    }

    public function onFlush(OnFlushEventArgs $args)
    {
        $em  = $args->getEntityManager();
        $uow = $em->getUnitOfWork();

        // before you ask, `(bool) array()` with empty array is `false`
        if (
            $uow->getScheduledEntityInsertions()
            || $uow->getScheduledEntityUpdates()
            || $uow->getScheduledEntityDeletions()
            || $uow->getScheduledCollectionUpdates()
            || $uow->getScheduledCollectionDeletions()
        ) {
            // update the user here
            $this->user->setLastModifiedDate(new DateTime());
            $uow->recomputeSingleEntityChangeSet(
                $em->getClassMetadata(get_class($this->user)), 
                $this->user
            );
        }
    }

    public function getSubscribedEvents()
    {
        return array(Events::onFlush);
    }
}

只有当User包含要提交给DB的更改(工作单元实际上是您可能定义为应用程序级别的状态事务)时,才会将更改应用于配置的UnitOfWork对象。

您可以在任何时候通过调用ORM注册此订阅服务器。

代码语言:javascript
复制
$user         = $entityManager->find('User', 123);
$eventManager = $entityManager->getEventManager();
$subscriber   = new UpdateUserEventSubscriber($user);

$eventManager->addEventSubscriber($subscriber);
票数 6
EN

Stack Overflow用户

发布于 2013-03-07 21:00:42

很抱歉一开始给了你错误的答案,这应该会指引你朝着正确的方向前进(注意它并不完美)。

您需要实现两个事件。一个侦听OnFlush事件的人,其行为如下:

代码语言:javascript
复制
// This should listen to OnFlush events
public function updateLastModifiedTime(OnFlushEventArgs $event) {
    $entity = $event->getEntity();
    $entityManager = $event->getEntityManager();
    $unitOfWork = $entityManager->getUnitOfWork();

    if (count($unitOfWork->getScheduledEntityInsertions()) > 0 || count($unitOfWork->getScheduledEntityUpdates()) > 0) {
        // update the user here
        $this->user->setLastModifiedDate(new \DateTime());
    }
}

我们需要等待OnFlush事件,因为这是我们访问将要完成的所有工作的唯一机会。注意,我并没有将它包括在上面,但是如果您想要跟踪它的话,也有$unitOfWork->getScheduledEntityDeletions()

接下来,您需要另一个最后的事件侦听器,它侦听PostFlush事件,如下所示:

代码语言:javascript
复制
// This should listen to PostFlush events
public function writeLastUserUpdate(PostFlushEventArgs $event) {
    $entityManager = $event->getEntityManager();
    $entityManager->persist($this->user);
    $entityManager->flush($this->user);
}

一旦交易启动,不幸的是,要想获得拯救另一个实体的理论为时已晚。因此,我们可以在User处理程序中对OnFlush对象的字段进行更新,但实际上不能将其保存在那里。(您可能会找到一种方法来做到这一点,但它不受Doctrine的支持,并且必须使用UnitOfWork的一些受保护的API)。

但是,一旦事务完成,您可以立即执行另一个快速事务,以更新用户的日期时间。是的,这确实有一个不幸的副作用,就是没有在单个事务中执行。

票数 2
EN

Stack Overflow用户

发布于 2013-03-07 21:00:49

如果实体上没有任何更改,则不会调用@PreUpdate事件。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15281614

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档