4

我正在使用教义的事件侦听器类来实现数据库事件的日志记录。我正在使用 postUpdate 事件。我的 mongoDB 文档中有一个嵌入式文档。在 postUpdate 事件中,当我调用该$uow->getDocumentChangeSet($entity)方法时,我只获取更改集对象中的更改值。例如

[0]=>
  object(Tyre24\ProductBundle\Document\Translations)#1178 (1) {
    ["translations":protected]=>
    object(Doctrine\ODM\MongoDB\PersistentCollection)#1216 (10) {
      ["snapshot":"Doctrine\ODM\MongoDB\PersistentCollection":private]=>
      array(0) {
      }
      ["coll":"Doctrine\ODM\MongoDB\PersistentCollection":private]=>
      object(Doctrine\Common\Collections\ArrayCollection)#1217 (1) {
        ["_elements":"Doctrine\Common\Collections\ArrayCollection":private]=>
        array(1) {
          [0]=>
          object(Tyre24\ProductBundle\Document\Translation)#1227 (3) {
            ["key":protected]=>
            string(11) "testkey_new"
            ["language":protected]=>
            string(5) "xx_XX"
            ["value":protected]=>
            string(9) "testvalue"
          }
        }
      }
    }
  }
  [1]=>
  object(Tyre24\ProductBundle\Document\Translations)#1178 (1) {
    ["translations":protected]=>
    object(Doctrine\ODM\MongoDB\PersistentCollection)#1216 (10) {
      ["snapshot":"Doctrine\ODM\MongoDB\PersistentCollection":private]=>
      array(0) {
      }
      ["coll":"Doctrine\ODM\MongoDB\PersistentCollection":private]=>
      object(Doctrine\Common\Collections\ArrayCollection)#1217 (1) {
        ["_elements":"Doctrine\Common\Collections\ArrayCollection":private]=>
        array(1) {
          [0]=>
          object(Tyre24\ProductBundle\Document\Translation)#1227 (3) {
            ["key":protected]=>
            string(11) "testkey_new"
            ["language":protected]=>
            string(5) "xx_XX"
            ["value":protected]=>
            string(9) "testvalue"
          }
        }
      }
    }
  }
}

这里更改集数组的第一个元素应该反映嵌入文档的旧状态,但它始终在两个数组索引中显示相同的(新)文档。对于没有嵌入文档的文档,它可以正常工作。任何想法?

4

1 回答 1

3

我对Doctrine ODM(mongo)不是很熟悉,但是对Doctrine ORM比较熟悉,它们有很多相似之处。我已经构建了像您为 ORM 描述的那样的记录器,所以让我分享一下我的经验。

哪些事件和原因

我赞成使用 OnFlush 事件,因为它是一个时间点,所有写操作都可以在它们实际发生之前找到。因此,您可以获得一组即将发生的一致更改。

使用 ORM,使用 PostPersist、PostUpdate 和 PostDelete 会为时已晚,因为更改已经发生,并且无法获得可靠的更改集。

使用 PrePersist、PreUpdate 和 PreDelete,您不会得到一个时间点:PreUpdate 和 PreDelete 将在刷新操作中发生,但 PrePersist 在您调用persist()实体/文档时立即发生。

因此,在 OnFlush 侦听器中,我将收集所有实体/文档更改以及关联更改。我会将它们保存在内存中,直到 PostFlush 事件被调度。PostFlush 事件在所有内容都保存到数据库后立即发生,因此这是写入日志的安全点。换句话说:当flush操作由于任何原因失败时,日志不会被写入,因为我们实际上并没有持久化任何东西。

追踪什么

使用 ORM,总是可以检测到标量属性的更改。但是对象的变化是通过引用检测的。这意味着如果属性包含新对象,则检测到更改。但是当属性包含相同的对象时(尽管该对象本身已更改),则不会检测到更改。

这就是为什么,至少对于 ORM,具有更改集合的实体不会出现在$uow->getScheduledEntityInsertions()等的返回值中。我不确定,但我怀疑 ODM 的行为方式相同。

因此,在监听器中跟踪更改时,您必须使用所有这些方法:

  • $uow->getScheduledDocumentInsertions();
  • $uow->getScheduledDocumentUpserts();
  • $uow->getScheduledDocumentUpdates();
  • $uow->getScheduledDocumentDeletions();
  • $uow->getScheduledCollectionDeletions();
  • $uow->getScheduledCollectionUpdates();

其中最后两个将返回一个已更改的集合数组。从集合中,您可以获得拥有的实体/文档 ( $col->getOwner()),并使用 diff 方法 ($col->getInsertDiff()$col->getDeleteDiff()) 找出确切更改的内容。

我希望这可以帮助您找到解决方案!

于 2015-04-04T09:16:16.180 回答