У меня есть документ с встроенным документом. Когда я создаю объект в первый раз, все работает нормально, но когда я пытаюсь обновить документ, встроенный документ не обновляется.
/** @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 посмотреть значения встроенного документа, чтобы решить, нужно ли его обновлять?
Я столкнулся с такой же проблемой. Оказывается, UnitOfWork, кажется, терпит неудачу при вычислении наборов документов с другими встроенными документами, хотя я не смог понять, почему... В результате, когда я сравниваю фактическое значение и оригинал, единица работы показывает одно и то же значение для обоих. Говоря с вашим вариантом А, когда вы
$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();
Это заставляет блок работы распознавать документ docB документа $в качестве вновь установленного документа и будет очищать его, как ожидалось.
MongoDB имеет только атомные операции. У вас есть варианты: 1. Запросите документ, найдите подходящий поддокумент, обновите весь документ или его часть. Плюсы: простая логика Минусы: неатомные 2. Используйте оператор positional $, ваш поддокументы находятся в списке.