曾经在黑暗的深渊中,有一段时间在Symfony的土地深处,有一个沮丧的程序员。他尝试过并试过但不知何故,邪恶的教义一次又一次地被打击。恶棍Joins
,Associative tables
和One-to-Many/Many-to-One
也让他很难受。然后,在一个下午晚些时候StackOverflow
,它的社区来救援。
足够的童话故事。我的问题是我有三个表都应该引用同一个表来获取附件。
- Mail
- Order
- Ticket
这三个实体中的每一个都可以有附件。所以我建立了一个附件实体。
现在,我的数据库包含以下内容
Table: mails
- id
- from
- to
- message
Table attachments
- id
- name
- path
Table: orders
- id
- ...
Table: tickets
- id
- name
- description
- ...
Table attachment_associations
- id
- type
- parent_id
- attachment_id
我想做的是能够将订单,门票和邮件映射到相同的附件表。
然而,我坚持如何在学说中这样做。
我尝试使用以下方法。这确实得到了我正在寻找的记录。但我不知道如何使用此方法自动创建,更新或删除关联表(连接表)中的记录。
/**
* @ORM\ManyToMany(targetEntity="\...\...\Entity\Attachment")
* @ORM\JoinTable(name="attachment_associations",
* joinColumns={@ORM\JoinColumn(name="parentId", referencedColumnName="id")},
* inverseJoinColumns={
* @ORM\JoinColumn(name="attachmentId", referencedColumnName="id")
* }
* )
*/
protected $attachments;
如果删除邮件,订单或故障单,是否也会删除所有相应的附件?
答案 0 :(得分:4)
实现此目的的一种方法是实施mapped super class class table inheritance,其中performance implications来自其他实体。
虽然您需要根据具体项目判断{{3}}。
这是一个简单的例子:
映射的超类
<?php
namespace AcmeBundle\Model;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
* @ORM\InheritanceType("JOINED")
* @ORM\DiscriminatorColumn(name="type", type="string")
*/
abstract class SuperClass
{
/**
* @var int
*
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
protected $id;
/**
* @var Attachment[]
*
* @ORM\ManyToMany(targetEntity="Attachment", mappedBy="parents")
*/
protected $attachments = [];
/**
* Constructor
*/
public function __construct()
{
$this->attachments = new ArrayCollection();
}
// put setters/getters for $attachments here
}
和附件管理关联。
<?php
namespace AcmeBundle\Model;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class Attachment
{
/**
* @var int
*
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @var SuperClass
*
* @ORM\ManyToMany(targetEntity="SuperClass", inversedBy="attachments")
*/
private $parents;
/**
* Constructor
*/
public function __construct()
{
$this->parents = new ArrayCollection();
}
}
实体只是扩展超类
<?php
namespace AcmeBundle\Model;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class Ticket extends SuperClass
{
}
答案 1 :(得分:2)
通过使用带有连接表的单向一对多,可以在一个表中包含所有附件。 In doctrine this is done with a unidirectional Many-To-Many with a unique constraint on the join column。这意味着一个表具有附件,但不同的连接表连接到每个父表。
这种解决方案的缺点是它是单向的,意味着你的附件不知道关系的拥有方。
在完整代码中,这将是这样的:
AttachmentsTrait
包含附件的setter和getter以防止代码重复:
<?php
namespace Application\Entity;
use Doctrine\Common\Collections\Collection;
/**
* @property Collection $attachments
*/
trait AttachmentTrait
{
/**
* Add attachment.
*
* @param Attachment $attachment
* @return self
*/
public function addAttachment(Attachment $attachment)
{
$this->attachments[] = $attachment;
return $this;
}
/**
* Add attachments.
*
* @param Collection $attachments
* @return self
*/
public function addAttachments(Collection $attachments)
{
foreach ($attachments as $attachment) {
$this->addAttachment($attachment);
}
return $this;
}
/**
* Remove attachment.
*
* @param Attachment $attachments
*/
public function removeAttachment(Attachment $attachment)
{
$this->attachments->removeElement($attachment);
}
/**
* Remove attachments.
*
* @param Collection $attachments
* @return self
*/
public function removeAttachments(Collection $attachments)
{
foreach ($attachments as $attachment) {
$this->removeAttachment($attachment);
}
return $this;
}
/**
* Get attachments.
*
* @return Collection
*/
public function getAttachments()
{
return $this->attachments;
}
}
您的Mail
实体:
<?php
namespace Application\Entity;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;
class Mail
{
use AttachmentsTrait;
/**
* @var integer
* @ORM\Id
* @ORM\Column(type="integer", nullable=false)
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* @ORM\ManyToMany(targetEntity="Attachment")
* @ORM\JoinTable(name="mail_attachments",
* inverseJoinColumns={@ORM\JoinColumn(name="attachment_id", referencedColumnName="id")},
* joinColumns={@ORM\JoinColumn(name="mail_id", referencedColumnName="id", unique=true)}
* )
*/
$attachments;
/**
* Constructor
*/
public function __construct()
{
$this->attachments = new ArrayCollection();
}
}
您的Order
实体:
<?php
namespace Application\Entity;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;
class Order
{
use AttachmentsTrait;
/**
* @var integer
* @ORM\Id
* @ORM\Column(type="integer", nullable=false)
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* @ORM\ManyToMany(targetEntity="Attachment")
* @ORM\JoinTable(name="order_attachment",
* inverseJoinColumns={@ORM\JoinColumn(name="attachment_id", referencedColumnName="id")},
* joinColumns={@ORM\JoinColumn(name="order_id", referencedColumnName="id", unique=true)}
* )
*/
$attachments;
/**
* Constructor
*/
public function __construct()
{
$this->attachments = new ArrayCollection();
}
}
您的Ticket
实体:
<?php
namespace Application\Entity;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;
class Ticket
{
use AttachmentsTrait;
/**
* @var integer
* @ORM\Id
* @ORM\Column(type="integer", nullable=false)
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* @ORM\ManyToMany(targetEntity="Attachment")
* @ORM\JoinTable(name="ticket_attachment",
* inverseJoinColumns={@ORM\JoinColumn(name="attachment_id", referencedColumnName="id")},
* joinColumns={@ORM\JoinColumn(name="ticket_id", referencedColumnName="id", unique=true)}
* )
*/
$attachments;
/**
* Constructor
*/
public function __construct()
{
$this->attachments= new ArrayCollection();
}
}
如果您真的希望Attachment
知道另一方,您可以在其间添加一个额外的实体来管理它。这意味着将连接表本身设置为实体,例如:MailAttachment
,TicketAttachment
和OrderAttachment
。