如何在Doctrine MongoDB中更新嵌入式文档?

6

我有一个包含另一个文档的文档。当我第一次创建对象时,一切正常,但是当我尝试更新文档时,嵌入的文档没有被更新。

/** @MongoDB\Document */
class DocumentA
{
    /** @MongoDB\EmbedOne(targetDocument="DocumentB") **/
    protected $docB;

    /** @MongoDB\String */
    protected $valueA;
}

/** @MongoDB\EmbeddedDocument */
class DocumentB
{
    /** @MongoDB\String */
    protected $valueB;
}

我的应用程序会查询某个文档,更新它的值并将其持久化到数据存储中。

// Variant A – Does not work
$document = ... // find from data store
$document->setValueA('Hello World');
$document->getDocB()->setValueB('foo baz');

$om->persist($document);
$om->flush();

如果我不更新嵌入式文档,而是设置一个新的文档,一切都能正常工作:
// Variant B - Does work
$document = ... // find from data store
$document->setValueB('Hello World 2');
$document->setDocB(new DocumentB());
$document->getDocB()->setValueB('foo baz 2');

$om->persist($document);
$om->flush();

正如我所说,变量B是正常工作的。然而,在我的应用程序中,文档更加复杂,每次更新嵌入式文档时创建一个新对象是不切实际的。有没有一种方法告诉Doctrine ODM查看嵌入式文档的值以决定是否应该更新它?

2个回答

2

我遇到了完全相同的问题。结果发现UnitOfWork似乎无法计算嵌入其他文档的文档的更改集,尽管我还没有找出原因...因此,当我比较实际值和原始值时,工作单元显示两者的值相同。按照您的A变体,当您

$document->getDocB()->setValueB('foo baz');

工作单元显示“foo baz”作为旧值和新值,因此不会将其识别为更改并因此不会更新它。

无论如何,这导致了一种解决方法:

$document = ... // find from data store
$document->setValueA('Hello World');
$docB = $document->getDocB();
$docB->setValueB('foo baz');
$om->detach($docB);
$om->persist($document);
$om->flush();

这将使工作单元将$document的docB识别为新设置的文档,并按预期刷新它。

我在替换嵌入文档时遇到了问题。在我的情况下,DocumentB 不是一个嵌入式文档,而是一个文档。就像你在这里展示的那样,在对象上使用 detach 在这种情况下也可以起作用。 - Onema

0

MongoDB仅支持原子操作。 您有以下选项: 1. 查询文档,找到适当的子文档,更新整个文档或其部分。 优点:逻辑简单 缺点:非原子性 2. 如果您的子文档在列表中,请使用位置$运算符。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接