0

在学说2中,我有一个 OneToMany 关联:一个应用程序 <=> 许多 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);
    }
}

假设用户可以编辑已经存在的 ApplicationCost并且可以更改它的父 Application,我如何确保这个 agregate 字段是最新的?

我的做法是:

// 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 食谱并且我有版本控制(并且我使用了锁定机制)。我的问题与并发无关。


编辑:我创建了一些测试

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');
}

添加$cost->setApplication($this);addEntry后,两个测试都是绿色的。虽然我仍然想知道我是否可能错过了什么。

4

1 回答 1

0

好吧,我想我终于达到了预期的结果。我将对其进行描述以供将来参考以及可能遇到相同问题的任何人:

首先纠正类

// Application.php
public function addCost(ApplicationCost $cost)
{
    if (!$this->costs->contains($cost)) {
        $this->sumCosts += $cost->getBalance();
    }

    $this->costs[] = $cost;

    return $this;
}

public function removeCost(ApplicationCost $cost)
{
    if ($this->costs->contains($cost)) {
        $this->sumCosts -= $cost->getBalance();
    }

    $this->costs->removeElement($cost);
}

如果您将此与我的原始代码进行比较,您会发现只有更新聚合字段处于条件下。它不会受到伤害,因为集合不能保存重复元素并且不能删除不存在的元素。

其次,cascade={all}在关联的反面配置选项(即在Application.phpcosts内部)。因此,每当您添加/删除成本时,它们也会持续存在。

待续......(必须测试当我从拥有方更改应用程序并仅保留 ApplicationCost 时会发生什么 -> 新旧应用程序都会更新吗?)

于 2013-06-23T16:56:13.840 回答