dongwei5794 2017-03-01 20:14
浏览 112

Ramsey \ UUID不与Doctrine OneToOne协会合作

I am building a project management tool for my team in Symfony 3. I am using ramsey/uuid-doctrine for the IDs in the system.

So far, this hasn't been a problem with One-to-Many or Many-to-One associations, but when I try to persist a One-to-One association, Doctrine is not converting the associated entity to its UUID, and instead leaving a null value in the SQL.

In this example, I have a WikiPage which can have multiple WikiPageVersions. The WikiPage has a One-to-Many association with WikiPageVersion (the versions property: for all the versions of the page), but also a One-to-One (Unidirectional) association with WikiPageVersion (the currentVersion property: for the, well, current version).

The WikiPage also has a Many-to-One associations with Project (to track which project the wiki page is for) and that property is populated correctly.

The WikiPage Entity

/**
 * @ORM\Table(name="wiki_page")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\Project\WikiPageRepository")
 */
class WikiPage
{
/**
 * @var Uuid
 * @ORM\Id
 * @ORM\Column(type="uuid")
 */
protected $id;
/**
 * @var Project
 * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Project\Project", inversedBy="wikiPages")
 * @ORM\JoinColumn(name="project_id", referencedColumnName="id")
 */
protected $project;
/**
 * @var string
 * @ORM\Column(name="title", type="text")
 * @Assert\NotBlank()
 */
protected $title;
/**
 * @var HiveWikiPageVersion
 * @ORM\OneToOne(targetEntity="AppBundle\Entity\Project\WikiPageVersion", fetch="EAGER")
 */
protected $currentVersion;
/**
 * @var ArrayCollection
 * @ORM\OneToMany(targetEntity="AppBundle\Entity\Project\WikiPageVersion", mappedBy="wikiPage", cascade={"persist", "remove"})
 */
protected $versions;

// -- Class Methods
}

The WikiPageVersion Entity

/**
 * @ORM\Table(name="wiki_page_version")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\Project\WikiPageVersionRepository")
 */
class WikiPageVersion
{
    /**
     * @var Uuid
     * @ORM\Id
     * @ORM\Column(type="uuid")
     */
    protected $id;
    /**
     * @var WikiPage
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Project\WikiPage", inversedBy="versions")
     * @ORM\JoinColumn(name="wiki_page_id", referencedColumnName="id")
     * @Assert\NotBlank()
     */
    protected $wikiPage;
    /**
     * @var string
     * @ORM\Column(name="content", type="text")
     * @Assert\NotBlank()
     */
    protected $content;
    /**
     * @var string
     * @ORM\Column(name="version_comment", type="string", length=255)
     * @Assert\NotNull()
     */
    protected $versionComment;
    /**
     * @var HiveWikiPageVersion
     * @ORM\OneToOne(targetEntity="AppBundle\Entity\Project\WikiPageVersion")
     * @ORM\JoinColumn(name="previous_version", referencedColumnName="id")
     * @Assert\Type(type="Odev\Hive\Model\Entity\Project\WikiPageVersion")
     */
    protected $previousVersion;
    /**
     * @var \DateTimeInterface
     * @ORM\Column(name="created", type="datetime")
     * @Assert\NotBlank()
     */
    protected $created;
    /**
     * @var User
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\User")
     * @ORM\JoinColumn(name="created_by", referencedColumnName="id")
     * @Assert\NotBlank()
     */
    protected $createdBy;
}
// -- Methods

Troubleshooting So Far

  1. I can confirm that before persisting the WikiPage, that the WikiPageVersion has been associated.
  2. I can duplicate this same behaviour with my Project and WikiPageVersion entites (Project has a One-to-One association with WikiPage for the wiki homepage and WikiPageVersion has a One-to-One association with itself for the previous version). Only the One-to-One associations are not converting the UUID.
  3. I have the same problem when trying to persist from Symfony Controller or from when loading Doctrine fixtures.
  4. I have tried to trace down where the conversion occurs using xdebug, but I am not that versed in using a debugger and after 20 minutes of stepping through the debugger, I can't find where the conversion for that field happens. I'm either skipping past the loop it happens in or just missing it. After wasting an hour skipping through runs trying to find the problem, I had to give up.

Here is the error I get from Doctrine when I try to perist the WikiPage:

[Doctrine\DBAL\Exception\NotNullConstraintViolationException]
An exception occurred while executing 'INSERT INTO wiki_page (id, project_home, title, project_id, current_version_id) VALUES (?, ?, ?, ?, ?)' with params ["ddc1f51a-f5d9-489f-89bb-cd79f3393af0", 1
, "Technical Reviews Wiki", "5138b185-b10b-48ac-a102-bdea1139c911", null]:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'current_version_id' cannot be null

and the exception trace (this exception is from saving during fixtures loading):

Exception trace:
() at /home/vagrant/hive/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php:112
Doctrine\DBAL\Driver\AbstractMySQLDriver->convertException() at /home/vagrant/hive/vendor/doctrine/dbal/lib/Doctrine/DBAL/DBALException.php:128
Doctrine\DBAL\DBALException::driverExceptionDuringQuery() at /home/vagrant/hive/vendor/doctrine/dbal/lib/Doctrine/DBAL/Statement.php:177
Doctrine\DBAL\Statement->execute() at /home/vagrant/hive/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php:281
Doctrine\ORM\Persisters\Entity\BasicEntityPersister->executeInserts() at /home/vagrant/hive/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:1014
Doctrine\ORM\UnitOfWork->executeInserts() at /home/vagrant/hive/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:378
Doctrine\ORM\UnitOfWork->commit() at /home/vagrant/hive/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php:356
Doctrine\ORM\EntityManager->flush() at /home/vagrant/hive/src/Odev/Hive/Infrastructure/AppBundle/DataFixtures/ORM/LoadProjectData.php:89
Odev\Hive\Infrastructure\AppBundle\DataFixtures\ORM\LoadProjectData->load() at /home/vagrant/hive/vendor/doctrine/data-fixtures/lib/Doctrine/Common/DataFixtures/Executor/AbstractExecutor.php:121
Doctrine\Common\DataFixtures\Executor\AbstractExecutor->load() at /home/vagrant/hive/vendor/doctrine/data-fixtures/lib/Doctrine/Common/DataFixtures/Executor/ORMExecutor.php:88
Doctrine\Common\DataFixtures\Executor\ORMExecutor->Doctrine\Common\DataFixtures\Executor\{closure}() at n/a:n/a
call_user_func() at /home/vagrant/hive/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php:233
Doctrine\ORM\EntityManager->transactional() at /dev/shm/app/cache/dev/appDevDebugProjectContainer.php:5645
DoctrineORMEntityManager_00000000015ce1f5000000002a2c79364ae5d79093a662a969d1540330e84087->transactional() at /home/vagrant/hive/vendor/doctrine/data-fixtures/lib/Doctrine/Common/DataFixtures/Executor/ORMExecutor.php:90
Doctrine\Common\DataFixtures\Executor\ORMExecutor->execute() at /home/vagrant/hive/vendor/doctrine/doctrine-fixtures-bundle/Command/LoadDataFixturesDoctrineCommand.php:118
Doctrine\Bundle\FixturesBundle\Command\LoadDataFixturesDoctrineCommand->execute() at /home/vagrant/hive/vendor/symfony/symfony/src/Symfony/Component/Console/Command/Command.php:262
Symfony\Component\Console\Command\Command->run() at /home/vagrant/hive/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:848
Symfony\Component\Console\Application->doRunCommand() at /home/vagrant/hive/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:189
Symfony\Component\Console\Application->doRun() at /home/vagrant/hive/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Console/Application.php:80
Symfony\Bundle\FrameworkBundle\Console\Application->doRun() at /home/vagrant/hive/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:120
Symfony\Component\Console\Application->run() at /home/vagrant/hive/bin/console:29

At this point I am lost - if there is any suggestions of where I should be looking or if anyone else has run into this problem, I would love and guidance that could be provided.

Update

As requested by matteo:

Here is the load method of the fixture that creates the records and throws the error.

/**
 * {@inheritDoc}
 * @param ObjectManager $manager
 */
public function load(ObjectManager $manager)
{
    // Create ODEV Project Section
    $section = new ProjectSection(
        Uuid::uuid4(),
        'ODEV',
        'ODEV specific projects'
    );

    $manager->persist($section);
    $this->addReference('section-odev', $section);

    // Create Technical Review Project -> public
    $project = new Project(
        Uuid::uuid4(),
        'techreview',
        $section,
        'Technical Reviews',
        'Technical Reviews for Work Requests',
        false,
        false,
        $this->getReference('user-system'),
        $this->getReference('user-system'),
        '',
        $this->getReference('user-system')
    );

    // VarDumper::dump($project->getWikiHome()->getId());
    // VarDumper::dump($project->getCreatedBy()->getId());

    $manager->persist($project);
    $this->addReference('project-tech-review', $project);

    $manager->flush();
}

The two VarDumper::dump() commands were to confirm that the associations were getting created.

The actual WikiPage gets generated in the Project's constructor and the WikiPageVersion is generated in the WikiPages's constructor.

Here is Project's constructor:

public function __construct(
    string $id,
    string $identifier,
    ProjectSection $section,
    string $name,
    string $description,
    bool $private,
    bool $sensitive,
    User $owner,
    User $contact,
    string $homepage,
    User $createdBy
) {
    $this->id = Uuid::fromString($id);
    $this->identifier = $identifier;
    $this->projectSection = $section;
    $this->name = $name;
    $this->description = $description;
    $this->private = $private;
    $this->sensitive = $sensitive;
    $this->owner = $owner;
    $this->contact = $contact;
    $this->homepage = $homepage;

    $this->createdBy = $createdBy;
    $this->created = new \DateTimeImmutable();
    $this->updatedBy = $createdBy;
    $this->updated = new \DateTimeImmutable();

    $this->archived = false;
    $this->workRequest = null;

    // set up collections
    $this->teamMembers = new ArrayCollection();
    $this->issues = new ArrayCollection();

    $this->folders = new ArrayCollection($this->defaultFolders());
    $this->wikiHome = $this->defaultWikiPage();
    $this->wikiPages = new ArrayCollection([$this->wikiHome]);
    $this->labels = new ArrayCollection($this->defaultLabels());
    $this->milestones = new ArrayCollection($this->defaultMilestones());
}

protected function defaultWikiPage(): WikiPage
{
    return new WikiPage(Uuid::uuid4(), $this, $this->name.' Wiki', '', $this->createdBy);
}

And the constructor of WikiPage:

public function __construct(string $id, Project $project, string $title, string $content, User $createdBy)
{
    $this->id = Uuid::fromString($id);
    $this->project = $project;
    $this->title = $title;
    $this->content = $content;
    $this->created = new \DateTimeImmutable();
    $this->createdBy = $createdBy;

    $this->currentVersion = $this->createFirstVersion($content, $createdBy);
    $this->versions = new ArrayCollection([$this->currentVersion]);
}

protected function createFirstVersion(string $content, User $createdBy)
{
    return new WikiPageVersion(Uuid::uuid4(), $this, $content, $createdBy, 'Page Created');
}

Hope that helps.

  • 写回答

1条回答 默认 最新

  • doushang4293 2017-03-01 21:27
    关注

    When WikiPage Entity tries to INSERT it is trying to insert all its properties. Do a check for version and if === null unset the key index. then when the INSERT fires the parm array is only 4 keys.

    评论

报告相同问题?

悬赏问题

  • ¥15 Oracle中如何从clob类型截取特定字符串后面的字符
  • ¥15 想通过pywinauto自动电机应用程序按钮,但是找不到应用程序按钮信息
  • ¥15 MATLAB中streamslice问题
  • ¥15 如何在炒股软件中,爬到我想看的日k线
  • ¥15 51单片机中C语言怎么做到下面类似的功能的函数(相关搜索:c语言)
  • ¥15 seatunnel 怎么配置Elasticsearch
  • ¥15 PSCAD安装问题 ERROR: Visual Studio 2013, 2015, 2017 or 2019 is not found in the system.
  • ¥15 (标签-MATLAB|关键词-多址)
  • ¥15 关于#MATLAB#的问题,如何解决?(相关搜索:信噪比,系统容量)
  • ¥500 52810做蓝牙接受端