删除用户时虚拟多对多用户关系中的外键问题

Foreign Key issue in a virtual many-to-many user relationship when removing user

在我的 Symfony 应用程序中,我必须处理某种友谊请求。它基本上是用户之间的多对多关系,但是有一个 accepted 布尔值 属性 和一个 createdAt DateTime,因此我创建了一个独立的“友谊”实体而不是一个多对多用户实体中的许多关系。

问题是:我有一个 Sender 属性(与用户的一对多关系)和一个 recipient 属性(与用户的一对多关系)用户也是如此)。我在用户 属性 中将 orphanRemoval 设置为 true。

但是,如果我删除一个只有朋友的用户,而他是发件人,它会很好地删除朋友实体。但是如果他是好友请求的接收者,它就不起作用并且 returns 一个外键约束错误,更准确地说

SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (portail.friendship, CONSTRAINT FK_7234A45FE92F8F78 FOREIGN KEY (recipient_id) REFERENCES user (id)).

我估计这与用户在我的友谊实体中出现两次有关,显然,addFriendship() / removeFriendship() 方法中似乎只提到了发件人,但我不确定如何解决它,我想知道我是否没有以正确的方式解决这个问题,以及我可以做些什么来改变它并让它发挥作用(即:删除所有与友谊相关的给用户,无论他是发件人还是收件人)。

下面是friendship实体,以及User实体中提到Friendship实体关系的部分。

<?php

namespace App\Entity;

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

/**
 * @ORM\Entity(repositoryClass=FriendshipRepository::class)
 */
class Friendship
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity=User::class, inversedBy="friendships")
     * @ORM\JoinColumn(nullable=false)
     */
    private ?User $sender;

    /**
     * @ORM\ManyToOne(targetEntity=User::class, inversedBy="friendships")
     * @ORM\JoinColumn(nullable=false)
     */
    private ?User $recipient;

    /**
     * @ORM\Column(type="boolean")
     */
    private ?bool $accepted;

    /**
     * @ORM\Column(type="datetime_immutable")
     */
    private ?\DateTimeImmutable $createdAt;


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

    public function getSender(): ?User
    {
        return $this->sender;
    }

    public function setSender(?User $sender): self
    {
        $this->sender = $sender;

        return $this;
    }

    public function getRecipient(): ?User
    {
        return $this->recipient;
    }

    public function setRecipient(?User $recipient): self
    {
        $this->recipient = $recipient;

        return $this;
    }

    public function getAccepted(): ?bool
    {
        return $this->accepted;
    }

    public function setAccepted(bool $accepted): self
    {
        $this->accepted = $accepted;

        return $this;
    }

    public function getCreatedAt(): ?\DateTimeImmutable
    {
        return $this->createdAt;
    }

    public function setCreatedAt(\DateTimeImmutable $createdAt): self
    {
        $this->createdAt = $createdAt;

        return $this;
    }

}

部分用户


    /**
     * @ORM\OneToMany(targetEntity=Friendship::class, mappedBy="sender", orphanRemoval=true)
     */
    private $friendships;

    /**
     * @return Collection|Friendship[]
     */
    public function getFriendships(): Collection
    {
        return $this->friendships;
    }

    public function addFriendship(Friendship $friendship): self
    {
        if (!$this->friendships->contains($friendship)) {
            $this->friendships[] = $friendship;
            $friendship->setSender($this);
        }

        return $this;
    }

    public function removeFriendship(Friendship $friendship): self
    {
        if ($this->friendships->removeElement($friendship)) {
            // set the owning side to null (unless already changed)
            if ($friendship->getSender() === $this) {
                $friendship->setSender(null);
            }
        }

        return $this;
    }

Arleigh 确实是正确的。我做错的是设置了相同的名称,即 Friendships,同时更新我的​​ friendship 实体以获得用户中的两个关系,无论他是 sender 还是 recipient。我认为这会让我更容易地在我的控制器和 twig 模板中获得与用户相关的所有 friendships,无论它们是 recipient 还是 sender 但最后,所有它确实让一切都出错了。

我通过在我的用户中有两个单独的属性来修复它,friendshipRequestsSent(由 Friendship 实体的 sender 字段映射)和 friendshipRequestsReceived(映射通过 Friendship 实体的 recpient 字段)以及相关属性的方法和类型。这就是我现在 User 实体中的样子

    /**
     * @ORM\OneToMany(targetEntity=Friendship::class, mappedBy="sender", orphanRemoval=true)
     */
    private $friendshipRequestsSent;

    /**
     * @ORM\OneToMany(targetEntity=Friendship::class, mappedBy="recipient", orphanRemoval=true)
     */
    private $friendshipRequestsReceived;


    public function __construct()
    {
        $this->userSkills = new ArrayCollection();
        $this->experiences = new ArrayCollection();
        $this->missions = new ArrayCollection();
        $this->friendshipRequestsSent = new ArrayCollection();
        $this->friendshipRequestsReceived = new ArrayCollection();
    }
    /**
     * @return Collection|Friendship[]
     */
    public function getFriendshipRequestsSent(): Collection
    {
        return $this->friendshipRequestsSent;
    }

    public function addFriendshipRequestSent(Friendship $friendship): self
    {
        if (!$this->friendshipRequestsSent->contains($friendship)) {
            $this->friendshipRequestsSent[] = $friendship;
            $friendship->setSender($this);
        }

        return $this;
    }

    public function removeFriendshipRequestSent(Friendship $friendship): self
    {
        if ($this->friendshipRequestsSent->removeElement($friendship)) {
            // set the owning side to null (unless already changed)
            if ($friendship->getSender() === $this) {
                $friendship->setSender(null);
            }
        }

        return $this;
    }


    /**
     * @return Collection|Friendship[]
     */
    public function getFriendshipRequestsReceived(): Collection
    {
        return $this->friendshipRequestsReceived;
    }

    public function addFriendshipRequestReceived(Friendship $friendship): self
    {
        if (!$this->friendshipRequestsReceived->contains($friendship)) {
            $this->friendshipRequestsReceived[] = $friendship;
            $friendship->setSender($this);
        }

        return $this;
    }

    public function removeFriendshipRequestReceived(Friendship $friendship): self
    {
        if ($this->friendshipRequestsReceived->removeElement($friendship)) {
            // set the owning side to null (unless already changed)
            if ($friendship->getSender() === $this) {
                $friendship->setSender(null);
            }
        }

        return $this;
    }

这就是我的 Friendship 实体 senderrecipient 属性的声明方式


    /**
     * @ORM\ManyToOne(targetEntity=User::class, inversedBy="friendshipRequestsSent")
     * @ORM\JoinColumn(nullable=false)
     */
    private ?User $sender;

    /**
     * @ORM\ManyToOne(targetEntity=User::class, inversedBy="friendshipRequestsReceived")
     * @ORM\JoinColumn(nullable=false)
     */
    private ?User $recipient;