madflow
madflow

Reputation: 8520

Populating a Doctrine Entity with a native query and an unmanaged field

I would like to create a Doctrine Native Query, which creates a list of properly hydrated Entity objects. These should be "known" to the entity manager. There is one field in the Entity, which should not be managed by the ORM. It should not be part of any query etc. Therefore it has no ORM specific metadata attached to it. In the example below, this field is called "version". It should be populated by the native query result.

Is there a way this can be achieved with native queries?

When I try to use addFieldResult

$rsm = new ResultSetMapping();
$rsm->addEntityResult(Foo::class, 'f');
$rsm->addFieldResult('f', 'id', 'id');
$rsm->addFieldResult('f', 'name', 'name');
$rsm->addFieldResult('f', 'version', 'version');
$query = $this->entityManager->createNativeQuery("SELECT id, name, '1.0.1' as version  FROM foo", $rsm);
$foos = $query->getResult();

I get

In AbstractHydrator.php line 422:

  Warning: Undefined array key "version"

Which makes sense, since the "version" has no metadata.

When I treat the Entity object as an DTO:

$rsm->addScalarResult('id', 'id', 'integer');
$rsm->addScalarResult('name', 'name', 'string');
$rsm->addScalarResult('version', 'version', 'string');
$rsm->newObjectMappings['id']  = [
            'className' => Foo::class,
            'objIndex'  => 0,
            'argIndex'  => 0,
];
$rsm->newObjectMappings['name']  = [
            'className' => Foo::class,
            'objIndex'  => 0,
            'argIndex'  => 1,
];
$rsm->newObjectMappings['version']  = [
            'className' => Foo::class,
            'objIndex'  => 0,
            'argIndex'  => 2,
];

This creates "objects" of the Entity - but these are then "unknown" to the entity manager and we get errors like Detached entity App\Entity\Foo@388 cannot be removed when trying to remove any of the results objects.

This is the Entity class:

<?php

namespace App\Entity;

use App\Repository\FooRepository;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity(repositoryClass: FooRepository::class)]
class Foo
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 255)]
    private ?string $name = null;

    private ?string $version = null;

    // this is needed by the scalar results mapping.
    // public function __construct(?int $id, ?string $name, ?string $version)
    // {
    //     $this->id = $id;
    //     $this->name = $name;
    //     $this->version = $version;
    // }


    public function getId(): ?int
    {
        return $this->id;
    }

    public function getName(): ?string
    {
        return $this->name;
    }

    public function setName(string $name): static
    {
        $this->name = $name;

        return $this;
    }

    public function getVersion(): ?string
    {
        return $this->version;
    }

    public function setVersion(string $version): static
    {
        $this->version = $version;

        return $this;
    }
}

Upvotes: 0

Views: 14

Answers (0)

Related Questions