doctrine2 には OneToMany 関連付けがあります: One Application <=> Many ApplicationCost
// Application.php
/**
* @ORM\OneToMany(targetEntity="ApplicationCost", mappedBy="application", orphanRemoval=true)
*/
protected $costs;
// ApplicationCost.php
/**
* @ORM\ManyToOne(targetEntity="Application", inversedBy="costs")
* @ORM\JoinColumn(name="application_id", referencedColumnName="id")
*/
protected $application;
Application エンティティには、集計フィールドsumCostsがあります。
/**
* @ORM\Column(type="decimal", scale=2)
*/
protected $sumCosts;
addCost と removeCost が呼び出されると更新されます。
// Application.php
public function addCost(ApplicationCost $cost)
{
if (!$this->costs->contains($cost)) {
$this->sumCosts += $cost->getBalance();
$this->costs[] = $cost;
$cost->setApplication($this);
}
return $this;
}
public function removeCost(ApplicationCost $cost)
{
if ($this->costs->contains($cost)) {
$this->sumCosts -= $cost->getBalance();
$this->costs->removeElement($cost);
}
}
User が既存の ApplicationCost を編集でき、その親 Application を変更できると仮定すると、この集計フィールドが最新であることを確認するにはどうすればよいですか?
私のアプローチは次のとおりです。
// ApplicationCost.php
public function setApplication(Application $application = null)
{
if ($this->application !== null) {
$this->application->removeCost($this);
}
if ($application !== null) {
$application->addCost($this);
}
$this->application = $application;
return $this;
}
それはいいですか?それとも、ここで大きな間違いを犯していて、sumCosts が同期していない可能性がありますか?
編集: Doctrine の Aggregate Fields cookbook を読み、バージョン管理を行いました (そしてロック機構を使用しています)。私の質問は並行性に関するものではありません。
編集:いくつかのテストを作成しました
public function testSumCosts()
{
$app = new Application();
$costA = new ApplicationCost();
$costA->setBalance(150);
$costB = new ApplicationCost();
$costB->setBalance(100);
$costC = new ApplicationCost();
$costC->setBalance(50);
$app->addCost($costA);
$app->addCost($costB);
$app->addCost($costC);
$app->removeCost($costC);
$this->assertEquals(250, $app->sumCosts(), 'Costs are summed correctly');
}
public function testCostsChangeApplication()
{
$appA = new Application();
$appB = new Application();
$costA = new ApplicationCost();
$costA->setBalance(100);
$costB = new ApplicationCost();
$costB->setBalance(50);
$appA->addCost($costA);
$appB->addCost($costB);
$costA->setApplication($appB);
$costB->setApplication(null);
$this->assertEquals(0, $appA->sumCosts(), 'Costs are removed correctly');
$this->assertEquals(100, $appB->sumCosts(), 'Costs are added correctly');
}
addEntryに追加$cost->setApplication($this);
すると、両方のテストが緑色になります。何かを見逃したのではないかと思いますが。