默认情况下如何在主实体中获取子对象值的总和

时间:2016-10-21 19:18:57

标签: symfony doctrine-orm

我有一个PurchaseOrder实体,我有一个Payments实体。在PurchaseOrder实体内部,我正在尝试获取Payments.amountPaid的总和但是它不能按预期工作。理想情况下,$ allPaid应该具有每个PurchaseOrder的所有支付金额的总和。我正在学习本教程:enter link description here

这是我的PurchaseOrder实体:

class PurchaseOrder
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\OneToOne(targetEntity="RequestForEstimate", fetch="EAGER")
     * @ORM\JoinColumn(name="request_id", referencedColumnName="request_id")
     */
    private $request;

    /**
     * @ORM\OneToMany(targetEntity="Payment", mappedBy="purchaseOrder", orphanRemoval=true, cascade={"persist"}, fetch="EAGER")
     */
    private $payments;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="create_time", type="datetime")
     */
    private $createTime;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="update_time", type="datetime")
     */
    private $updateTime;

    /**
     * @ORM\ManyToOne(targetEntity="PurchaseOrderStatus", cascade={"persist"})
     */
    private $status;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="ship_date",type="datetime")
     */
    private $shipDate;

    private $allPaid = 0;


    public function getAllPaid()
    {
        foreach ($this->payments as $payment) {
            $this->allPaid += $payment->amountPaid();
        }
        return $this->allPaid;
    }
    /**
     * Get id
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }
    /**
     * Set createTime
     *
     * @param \DateTime $createTime
     *
     * @return PurchaseOrder
     */
    public function setCreateTime($createTime)
    {
        $this->createTime = $createTime;

        return $this;
    }

    /**
     * Get createTime
     *
     * @return \DateTime
     */
    public function getCreateTime()
    {
        return $this->createTime;
    }

    /**
     * Set updateTime
     *
     * @param \DateTime $updateTime
     *
     * @return PurchaseOrder
     */
    public function setUpdateTime($updateTime)
    {
        $this->updateTime = $updateTime;

        return $this;
    }

    /**
     * Get updateTime
     *
     * @return \DateTime
     */
    public function getUpdateTime()
    {
        return $this->updateTime;
    }

    /**
     * Set status
     *
     * @param integer $status
     *
     * @return PurchaseOrder
     */
    public function setStatus($status)
    {
        $this->status = $status;

        return $this;
    }

    /**
     * Get status
     *
     * @return int
     */
    public function getStatus()
    {
        return $this->status;
    }

    /**
     * Set shipDate
     *
     * @param \DateTime $shipDate
     *
     * @return PurchaseOrder
     */
    public function setShipDate($shipDate)
    {
        $this->shipDate = $shipDate;

        return $this;
    }

    /**
     * Get shipDate
     *
     * @return \DateTime
     */
    public function getShipDate()
    {
        return $this->shipDate;
    }

    /**
     * Set requestForEstimate
     *
     * @param \InboundBundle\Entity\RequestForEstimate $requestForEstimate
     *
     * @return PurchaseOrder
     */
    public function setRequestForEstimate(\InboundBundle\Entity\RequestForEstimate $requestForEstimate = null)
    {
        $this->requestForEstimate = $requestForEstimate;

        return $this;
    }

    /**
     * Get requestForEstimate
     *
     * @return \InboundBundle\Entity\RequestForEstimate
     */
    public function getRequestForEstimate()
    {
        return $this->requestForEstimate;
    }

    /**
     * Set requestId
     *
     * @param \InboundBundle\Entity\RequestForEstimate $requestId
     *
     * @return PurchaseOrder
     */
    // public function setRequest(\InboundBundle\Entity\RequestForEstimate $request = null)
    // {
    //     $this->request = $request;
    //     $request->setRequestId($this);
    //     return $this;
    // }
    public function setPayments(Payment $payments = null)
    {
        $this->payments = $payments;

        return $this;
    }


    /**
     * Get requestId
     *
     * @return \InboundBundle\Entity\RequestForEstimate
     */
    public function getRequest()
    {
        return $this->request;
    }

    /**
     * Set request
     *
     * @param \InboundBundle\Entity\RequestForEstimate $request
     *
     * @return PurchaseOrder
     */


    /**
     * Constructor
     */
    public function __construct()
    {
        $this->payments = new \Doctrine\Common\Collections\ArrayCollection();
    }

    /**
     * Add payment
     *
     * @param \InboundBundle\Entity\Payment $payment
     *
     * @return PurchaseOrder
     */
    public function addPayment(\InboundBundle\Entity\Payment $payment)
    {
        $this->payments[] = $payment;

        return $this;
    }

    /**
     * Remove payment
     *
     * @param \InboundBundle\Entity\Payment $payment
     */
    public function removePayment(\InboundBundle\Entity\Payment $payment)
    {
        $this->payments->removeElement($payment);
    }

    /**
     * Get payments
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getPayments()
    {
        return $this->payments;
    }

    /**
     * Set request
     *
     * @param \InboundBundle\Entity\RequestForEstimate $request
     *
     * @return PurchaseOrder
     */
    public function setRequest(\InboundBundle\Entity\RequestForEstimate $request = null)
    {
        $this->request = $request;

        return $this;
    }
}

付款实体:

class Payment
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="PurchaseOrder", inversedBy="payments", cascade={"persist", "detach"})
     * @ORM\JoinColumn(name="purchase_order", referencedColumnName="id")
     */
    private $purchaseOrder;
    /**
     * @var \DateTime
     *
     * @ORM\Column(name="create_time", type="datetime")
     */
    private $createTime;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="update_time", type="datetime")
     */
    private $updateTime;
    /**
     * @var int
     *
     * @ORM\Column(name="creator", type="integer")
     */
    private $creator;
    /**
     * @var string
     *
     * @ORM\Column(name="amount_paid", type="decimal", precision=10, scale=2)
     */
    private $amountPaid;

    /**
     * @ORM\ManyToOne(targetEntity="PaymentType", cascade={"persist"})
     * @ORM\JoinColumn(name="payment_type", referencedColumnName="id")
     */
    private $paymentType;
    /**
     * @var string
     *
     * @ORM\Column(name="external_transaction_id", type="string", length=255)
     */
    private $externalTransactionId;

    /**
     * @var string
     *
     * @ORM\Column(name="including_fees", type="decimal", precision=10, scale=2)
     */
    private $includingFees;





    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set createTime
     *
     * @param \DateTime $createTime
     *
     * @return Payment
     */
    public function setCreateTime($createTime)
    {
        $this->createTime = $createTime;

        return $this;
    }

    /**
     * Get createTime
     *
     * @return \DateTime
     */
    public function getCreateTime()
    {
        return $this->createTime;
    }

    /**
     * Set updateTime
     *
     * @param \DateTime $updateTime
     *
     * @return Payment
     */
    public function setUpdateTime($updateTime)
    {
        $this->updateTime = $updateTime;

        return $this;
    }

    /**
     * Get updateTime
     *
     * @return \DateTime
     */
    public function getUpdateTime()
    {
        return $this->updateTime;
    }

    /**
     * Set creator
     *
     * @param integer $creator
     *
     * @return Payment
     */
    public function setCreator($creator)
    {
        $this->creator = $creator;

        return $this;
    }

    /**
     * Get creator
     *
     * @return integer
     */
    public function getCreator()
    {
        return $this->creator;
    }

    /**
     * Set amountPaid
     *
     * @param string $amountPaid
     *
     * @return Payment
     */
    public function setAmountPaid($amountPaid)
    {
        $this->amountPaid = $amountPaid;

        return $this;
    }

    /**
     * Get amountPaid
     *
     * @return string
     */
    public function getAmountPaid()
    {
        return $this->amountPaid;
    }

    /**
     * Set paymentType
     *
     * @param string $paymentType
     *
     * @return Payment
     */
    public function setPaymentType($paymentType)
    {
        $this->paymentType = $paymentType;

        return $this;
    }

    /**
     * Get paymentType
     *
     * @return string
     */
    public function getPaymentType()
    {
        return $this->paymentType;
    }

    /**
     * Set externalTransactionId
     *
     * @param string $externalTransactionId
     *
     * @return Payment
     */
    public function setExternalTransactionId($externalTransactionId)
    {
        $this->externalTransactionId = $externalTransactionId;

        return $this;
    }

    /**
     * Get externalTransactionId
     *
     * @return string
     */
    public function getExternalTransactionId()
    {
        return $this->externalTransactionId;
    }

    /**
     * Set includingFees
     *
     * @param string $includingFees
     *
     * @return Payment
     */
    public function setIncludingFees($includingFees)
    {
        $this->includingFees = $includingFees;

        return $this;
    }

    /**
     * Get includingFees
     *
     * @return string
     */
    public function getIncludingFees()
    {
        return $this->includingFees;
    }

    /**
     * Set purchaseOrder
     *
     * @param \InboundBundle\Entity\PurchaseOrder $purchaseOrder
     *
     * @return Payment
     */
    public function setPurchaseOrder(\InboundBundle\Entity\PurchaseOrder $purchaseOrder = null)
    {
        $this->purchaseOrder = $purchaseOrder;

        return $this;
    }

    /**
     * Get purchaseOrder
     *
     * @return \InboundBundle\Entity\PurchaseOrder
     */
    public function getPurchaseOrder()
    {
        return $this->purchaseOrder;
    }
}

当我转储对象时,它显示默认情况下allPaid为0:

enter image description here

2 个答案:

答案 0 :(得分:2)

Matko的答案有效,但你的问题暗示你(或者至少你是)遗漏了一些基本的东西。

在原始代码中,内部(私有)allPaid属性初始化为零。您的getAllPaid()方法计算实际值并返回它。如上所述,getAllPaid()将在每次调用时迭代付款集合。

转储实体时,$allPaid属性为零,因为您在调用 getAllPaid()之前转储了。如果您调用getAllPaid()然后转储,您将看到它包含计算值。这是因为getAllPaid()在此过程中设置了该值。或者,不是转储(并查看未初始化的内部值),而是通过实际调用getAllPaid()进行测试,并查看是否返回了正确的值。

Matko解决方案的弱点在于它每次都急切地加载集合。在某些情况下,您可能需要在不加载所有付款的情况下加载PurchaseOrder。

由于$allPaid是私有的,因此您始终会使用getAllPaid()来访问该值。

要改进您的代码,我会记住 $allPaid

  1. 初始化private $allPaid = null;null的语义更合适,因为在初始化时,该值不为零。这是未知的。

  2. 在getAllPaid()中,添加$this->allPaid !== null的检查,如果是,请提前返回。这样,重复调用getAllPaid()不会每次都重新计算该值。

  3. 请务必在付款收集更改时清除备忘录。 PurchaseOrder::addPayment()PurchaseOrder::removePayment()都应将$this->allPaid设置为null,强制在下次调用getAllPaid()时重新计算该值。

  4. 最后,删除PurchaseOrder::payments上的急切fetchmode。如果您想在知道自己需要它们的情况下急切加载它们,可以在查询中获取它们。

答案 1 :(得分:1)

您应该使用Doctrine2 postLoad event。实体从数据库加载到当前EntityManager或刷新操作应用到实体后,实体会发生 postLoad 事件。

...
use Doctrine\ORM\Mapping as ORM;
...

/**
 * ... 
 * @ORM\HasLifecycleCallbacks
 * ...
 */
class PurchaseOrder
{
    ...

    private $allPaid = null;

    /**
     * @ORM\PostLoad
     */
    public function getAllPaid()
    {
        if (null === $this->allPaid) {
            foreach ($this->payments as $payment) {
                $this->allPaid += $payment->amountPaid();
            }
        }

        return $this->allPaid;
    }
}