Doctrine 中的 OneToMany 和 ManyToOne 关系 - 奇怪的映射错误

Posted

技术标签:

【中文标题】Doctrine 中的 OneToMany 和 ManyToOne 关系 - 奇怪的映射错误【英文标题】:OneToMany and ManyToOne relation in Doctrine - strange mapping error 【发布时间】:2021-06-16 18:54:19 【问题描述】:

我有两个像这样映射的实体:

namespace App\Entity\Email;


use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Contract\Entity\BlameableInterface;
use Knp\DoctrineBehaviors\Contract\Entity\SoftDeletableInterface;
use Knp\DoctrineBehaviors\Contract\Entity\TimestampableInterface;
use Knp\DoctrineBehaviors\Model\Blameable\BlameableTrait;
use Knp\DoctrineBehaviors\Model\SoftDeletable\SoftDeletableTrait;
use Knp\DoctrineBehaviors\Model\Timestampable\TimestampableTrait;


/**
 * @ORM\Entity(repositoryClass="App\Repository\Email\EmailRepository")
 */
class Email implements SoftDeletableInterface, TimestampableInterface, BlameableInterface

    use SoftDeletableTrait;

    use TimestampableTrait;

    use BlameableTrait;

    /**
     * @ORM\Column(type="integer")
     * @ORM\Id()
     * @ORM\GeneratedValue()
     */
    private ?int $id = null;

    ...

    /**
     * @var Collection|EmailAddress[]
     * @ORM\OneToMany(targetEntity="App\Entity\Email\EmailAddress", mappedBy="sentEmail", cascade="all", orphanRemoval=true)
     */
    private ?Collection $senders = null;

    /***
     * @var Collection|EmailAddress[]
     * @ORM\OneToMany(targetEntity="App\Entity\Email\EmailAddress", mappedBy="receivedEmail", cascade="all", orphanRemoval=true)
     */
    private ?Collection $recipients = null;
    
    ...
     

namespace App\Entity\Email;


use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Contract\Entity\BlameableInterface;
use Knp\DoctrineBehaviors\Contract\Entity\SoftDeletableInterface;
use Knp\DoctrineBehaviors\Contract\Entity\TimestampableInterface;
use Knp\DoctrineBehaviors\Model\Blameable\BlameableTrait;
use Knp\DoctrineBehaviors\Model\SoftDeletable\SoftDeletableTrait;
use Knp\DoctrineBehaviors\Model\Timestampable\TimestampableTrait;

/**
 * @ORM\Entity()
 */
class EmailAddress implements SoftDeletableInterface, TimestampableInterface, BlameableInterface

    use SoftDeletableTrait;

    use TimestampableTrait;

    use BlameableTrait;

    /**
     * @ORM\Column(type="integer")
     * @ORM\Id()
     * @ORM\GeneratedValue()
     */
    private ?int $id = null;

    ...

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Email\Email", inversedBy="senders")
     * @ORM\JoinColumn()
     */
    private ?Email $sentEmail = null;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Email\Email", inversedBy="recipients")
     * @ORM\JoinColumn()
     */
    private ?Email $receivedEmail = null;

    ...
    

由于未知原因,我收到了来自 Doctrine 的消息:

The association App\Entity\Email\EmailAddress#receivedEmail refers to the inverse side field App\Entity\Email\Email#recipients which does not exist.

我的映射有什么问题?我真的没有看到任何错误。我已经让我的同事检查我的代码,他们也没有发现任何问题。奇怪的是,关系 sentEmail->senders 是根据原则正确映射的并且它正在工作。

我也尝试将 OneToMany 映射更改为 ManyToMany,例如 this,但我仍然遇到同样的错误。

编辑 1:

数据库中的日期: 表格电子邮件

id | created_by_id | updated_by_id | deleted_by_id | deleted_at | created_at | updated_at | subject | content
1  | NULL          | NULL          | NULL          | NULL       | 1616156920 | 1616156920 | Test    | Test

表格 email_address

id | created_by_id | updated_by_id | deleted_by_id | address        | deleted_at | created_at | updated_at | sent_email_id | received_email_id
1  | NULL          | NULL          | NULL          | test1@test.com | NULL       | 1616156920 | 1616156920 | NULL          | 1
2  | NULL          | NULL          | NULL          | test2@test.com | NULL       | 1616156920 | 1616156920 | 1             | NULL

【问题讨论】:

什么时候收到错误信息?我做了一个简单的测试用例,没有 knp 的东西和教义:schema:create 工作正常。不用说,但我还是会说,尝试清除缓存。 我已经尝试清除缓存等。这个错误可以在 Symfony 调试工具栏中看到,并且关联不正常。在变量$recipients 中获取实体电子邮件而不是集合类后,有NULL 并且项目未加载(它们存在于数据库中)。 只是为了好玩,请仔细检查 email_address 表中的 received_email_id 是否具有预期值。 我已编辑问题,使其包含数据库中的行 你是否像这样在 __construct 中初始化集合 $this->recipients = new ArrayCollection()? 【参考方案1】:

这个问题/答案可能在“错字”的标题下,但我认为讨论起来可能很有趣。

问题出在这里:

/***
 * @var Collection|EmailAddress[]
 * @ORM\OneToMany(targetEntity="App\Entity\Email\EmailAddress", mappedBy="receivedEmail", cascade="all", orphanRemoval=true)
     */
private ?Collection $recipients = null;

注释块开头的额外星号 /*** 导致 Doctrine 跳过了收件人属性。但一切似乎都还好。数据库表和索引都按预期生成。

我做了一个简单的控制台命令来插入一个电子邮件实体,并很快注意到插入了发件人地址,但没有插入收件人地址。三重检查了各种方法,但仍然没有成功。显式持久化地址是可行的,但级联选项应该已经解决了这个问题。当然,即使在插入实体之后,也无法检索收件人地址。

在某些时候,我注意到 /*** 并将其更改为 /** 并且一切都按预期工作。与刷新浏览器和在调试栏中四处寻找相比,使用控制台命令进行测试有很大帮助。

从好的方面来说,如果您需要暂时删除注释,那么只需添加一个星号基本上与注释掉它是一样的。

【讨论】:

谢谢。你的眼睛真的很敏锐:D

以上是关于Doctrine 中的 OneToMany 和 ManyToOne 关系 - 奇怪的映射错误的主要内容,如果未能解决你的问题,请参考以下文章

EntityAudit - Doctrine2:可能在 OneToMany 和 OneToOne 中使用相同的实体

Symfony2 项目中的 Doctrine2 映射问题

覆盖Doctrine 2继承中的inversedBy映射

Doctrine 不会在我的 OneToMany 关联中保存数据

Doctrine2 - 无法删除具有单向 oneToMany 关系的实体

Symfony 3 - Doctrine 2 - 在 oneToMany 关系上的 orderBy 不起作用