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 中使用相同的实体
Doctrine 不会在我的 OneToMany 关联中保存数据