我遇到了以下问题.应用程序需要能够克隆Season具有所有相关实体的实体.我在这个伟大的问题上受到启发- 一切都按照它应有的方式运作,但ManyToMany在路上存在关系问题.
请查看附图,其中显示了数据库图表的一小部分,显示了我遇到问题的部分.
我想达到的状态是有一个克隆一个的Price绑定到实体的现有 Offer实体.说清楚 - 我不能也绝不能克隆Offer实体,实体的新克隆实例Price必须绑定到主Price实体实例绑定的同一个实例.
offer_price克隆之前表的示例内容 offer_id | price_id
----------+----------
47 | 77
Run Code Online (Sandbox Code Playgroud)
offer_price克隆后表的预期内容 offer_id | price_id
----------+----------
47 | 77
47 | 79
Run Code Online (Sandbox Code Playgroud)
...假设PriceID 77是主记录Price,ID 79是绑定到同一Offer记录的新克隆实例.
/**
* @Entity
*/
class Price
{
...
/**
* @var \Doctrine\Common\Collections\Collection of Offer
* @ManyToMany(targetEntity="Offer", mappedBy="prices", cascade={"persist"})
*
* @get
* @set
* @add
* @remove
* @contains
*/
private $offers;
/**
* Class construct
*
* @return void
*/
public function __construct()
{
parent::__construct();
$this->offers = new ArrayCollection();
}
/**
* Clone entity
*
* @return void
*/
public function __clone()
{
if ($this->getId()) {
$this->setId(null);
$this->offers = new ArrayCollection();
}
}
/**
* Add and offer into offers collection
*
* @param Offer $offer
* @return self
*/
public function addOffer(Offer $offer)
{
$this->offers->add($offer);
return $this;
}
...
}
Run Code Online (Sandbox Code Playgroud)
/**
* @Entity
*/
class Offer
{
...
/**
* @var \Doctrine\Common\Collections\Collection of Price
* @ManyToMany(targetEntity="Price", inversedBy="offers", cascade={"persist"})
*
* @get
* @set
* @add
* @remove
* @contains
*/
private $prices;
/**
* Class construct
*
* @return void
*/
public function __construct()
{
parent::__construct();
$this->prices = new ArrayCollection();
}
...
}
Run Code Online (Sandbox Code Playgroud)
/**
* @Entity
*/
class Season
{
...
/**
* @var \Doctrine\Common\Collections\Collection of Price
* @OneToMany(targetEntity="Price", mappedBy="season", cascade={"persist", "remove"})
*
* @get
* @set
* @add
* @remove
* @contains
*/
private $prices;
/**
* Class construct
*
* @return void
*/
public function __construct()
{
parent::__construct();
$this->prices = new ArrayCollection();
}
/**
* Clone entity
*
* @return void
*/
public function __clone()
{
if ($this->getId()) {
$this->setId(null);
...
$priceClonedCollection = new ArrayCollection();
foreach ($this->prices as $price) {
$priceClone = clone $price;
$priceClone->setSeason($this);
foreach ($price->getOffers() as $offer) {
$priceClone->addOffer($offer);
}
$priceClonedCollection->add($priceClone);
}
$this->prices = $priceClonedCollection;
...
}
}
...
}
Run Code Online (Sandbox Code Playgroud)
我所处的状态是我拥有所需的关系中的所有对象,但只有在整个集合被持久化之前.通过持久保存父对象(Season)来刷新所有对象之后,除了ManyToMany绑定表之外,所有其他对象都会保持级联,除了没有添加新记录的绑定表.
到目前为止我在应用程序中使用的解决方案非常脏.刷新所有持久化对象后,我只是迭代Offer绑定到Price实例的记录(因为它们正确地相互绑定)并存储所有随后被手动插入数据库的ID.这个解决方案显然不理想,非常脆弱.
...
/**
* Return an array consisting of mappings that have to be inserted manually
*
* @param Season $season
* @return array
*/
public function getCloneBindingHack(Season $clone)
{
foreach ($clone->getPrices() as $price) {
foreach ($price->getOffers() as $offer) {
$bindingHack[] = [
'offer_id' => $offer->getId(),
'price_id' => $price->getId(),
];
}
}
return $bindingHack ?? [];
}
...
Run Code Online (Sandbox Code Playgroud)
因此,我对如何坚持这样的关系感兴趣.我认为有一个优雅的解决方案我只是missig,因为这些操作在现实世界的场景中非常普遍.但也许Doctrine2无法做到这一点,"你必须自己做,因为Doctrine无法帮助你"也可能是一个有效的答案(这将使ORM相当无用的恕我直言).
我想补充-的情况下,对象上都在两侧ManyToMany关系正在新创建和坚持,一切正常,因为它应该,所以我推测的绑定表ManyToMany关系正确注解.
PHP版本7.0.22
Doctrine2 ORM版本2.4.8
注意:我已经读过这个问题,但它没有解决同样的问题.
对于您的问题:这是因为您没有将报价对象链接到价格克隆(侧面需要mappedBy)。尝试这样的事情:
/**
* Clone entity
*
* @return void
*/
public function __clone()
{
if ($this->getId()) {
$this->setId(null);
...
$priceClonedCollection = new ArrayCollection();
foreach ($this->prices as $price) {
$priceClone = clone $price;
$priceClone->setSeason($this);
foreach ($price->getOffers() as $offer) {
$offer->addPrice($priceClone);
$priceClone->addOffer($offer);
}
$priceClonedCollection->add($priceClone);
}
$this->prices = $priceClonedCollection;
...
}
}
Run Code Online (Sandbox Code Playgroud)
对于你丑陋的部分:这个问题已经被问过并且答案已经提出了这个包
| 归档时间: |
|
| 查看次数: |
250 次 |
| 最近记录: |