我必须拥有实体:Budget
和BudgetSpendingLimit
。
<?php
namespace Issue\Entity\Budget;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="budgets")
*/
class Budget
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue
* @var int|null
*/
protected $id;
/**
* @ORM\Column(type="integer")
* @var int
*/
protected $amount;
/**
* @ORM\OneToOne(targetEntity="BudgetSpendingLimit", mappedBy="budget", orphanRemoval=true, cascade={"all"})
* @var \Issue\Entity\Budget\BudgetSpendingLimit|null
*/
protected $spendingLimit;
public function __construct()
{
$this->id = null;
$this->amount = 0;
$this->spendingLimit = null;
}
public function applySpendingLimit(int $limit): void
{
$this->spendingLimit = new BudgetSpendingLimit($this, $limit);
}
public function offSpendingLimit(): void
{
$this->spendingLimit = null;
}
}
<?php
namespace Issue\Entity\Budget;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="budget_spending_limits")
*/
class BudgetSpendingLimit
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue
* @var int|null
*/
protected $id;
/**
* @ORM\OneToOne(targetEntity="Budget", inversedBy="spendingLimit")
* @ORM\JoinColumn(name="budget_id")
* @var \Issue\Entity\Budget\Budget
*/
protected $budget;
/**
* @ORM\Column(type="integer")
* @var int
*/
protected $hiLimit;
public function __construct(Budget $budget, int $hiLimit)
{
$this->id = null;
$this->budget = $budget;
$this->hiLimit = $hiLimit;
}
}
我想使用孤立删除来创建和删除BudgetSpendingLimit
至Budget
。
下一个代码段正在运行。
$budget = $em->find(Budget::class, 9);
$budget->offSpendingLimit();
$em->persist($budget);
$em->flush();
它将创建一个在表之间具有“左连接”的SQL查询。因此,两个实体均已加载,并且UnitOfWorks包含正确的“ originalEntityData”快照。它允许为孤儿计算正确的“删除”查询。
但是下一个代码段也将两个实体都加载到内存中,但是不会将“ BudgetSpendingLimit”实例作为“ Budget”的子代放置在“ originalEntityData”快照中。
$budget = $em->createQueryBuilder()
->select('b')
->from(Budget::class, 'b')
->where('b = :id')
->setParameter('id', 9)
->getQuery()
->getSingleResult();
$budget->offSpendingLimit();
$em->persist($budget);
$em->flush();
因此,此代码仅执行任何操作,而孤立行仍在表中。
可以通过在查询生成器中添加join
来解决,但是很遗憾,我们已经有一个庞大的代码库,并且需要花费很多时间来修复所有位置。
还有另一种解决问题的方法吗?
据我所知,在这种情况下,延迟加载不起作用。我怀疑这是因为拥有方是BudgetSpendingLimit
,因为它拥有inversedBy
属性。由于它是一对一的双向关联,因此您可以选择拥有的一方。
因此,我相信切换拥有权的一方将解决您的问题,尽管我目前无法对其进行测试。或者您可以使用联接,这将是一个更好的解决方案性能:
$budget = $em->createQueryBuilder()
->select('b')
->from(Budget::class, 'b')
->leftJoin('b.spendingLimit', 'sl')
->where('b = :id')
->setParameter('id', 9)
->getQuery()
->getSingleResult();