Skip to content

Embedded documents with targetDocument and discriminatorMap property do not save discriminatorField #2203

Open
@Steveb-p

Description

@Steveb-p
Q A
Version 2.1.0

Support Question

tl;dr
When using targetDocument and discriminatorMap annotation property for EmbedMany (I believe EmbedOne as well) embedded documents do not save discriminator property.

I believe it should be mentioned in the docs that those two should not be mixed.
If possible I would either allow targetDocumentto coexist with discriminatorMap as a "sanity check" when document passed is expected to be a specific class / interface.
Otherwise, I would throw an exception if they are used together.

Context:
I was extending an existing document to include a new type of embedded document with new properties. I had a document looking like this:

use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;

/**
 * @ODM\Document
 */
class Order 
{
    /**
     * @ODM\EmbedMany(targetDocument=LegacyClass::class)
     */
    private $embedded;
}

then I wanted to introduce another possible target document:

use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;

/**
 * @ODM\Document
 */
class Order 
{
    /**
     * @ODM\EmbedMany(
     *     targetDocument=AbstractClass::class),
     *     strategy="atomicSetArray",
     *     discriminatorField="type",
     *     discriminatorMap={
     *         "legacy"=LegacyClass::class,
     *         "statistic_aggregate"=NewClass::class,
     *     },
     *     defaultDiscriminatorValue="legacy",
     */
    private $embedded;
}

However, this resulted in type property to never be set.

While documents inserted into this embedded collection were NewClass instances and have it's property, when trying to read ODM was not finding type property and tried to instantiate LegacyClass.

Therefore I think that docs should explicitly warn about mixing those two annotations (targetDocument & discriminatorMap).

EDIT: A test that shown this misbehaving in my application:

use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;

class OrderTest extends KernelTestCase
{
    public function testEmbeddedDocumentsWorkCorrectly(): void
    {
        self::bootKernel();
        $dm = self::$container->get('doctrine_mongodb.odm.default_document_manager');

        $order = new Order();
        $order->addClass(new NewClass());
        $order->addClass(new LegacyClass());
        $dm->persist($order);
        $dm->flush();
        $id = $order->getId();
        $dm->clear();

        /** @var Order $order */
        $order = $dm->find(Order::class, $id);
        [ $reference, $legacyReference ] = $order->getClasses()->toArray();
        $this->assertInstanceOf(NewClass::class, $reference);
        $this->assertInstanceOf(LegacyClass::class, $legacyReference);
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions