Symfony - 避免在preFlush Doctrine中存储相关实体

时间:2014-07-28 15:24:33

标签: symfony events doctrine-orm

我有一个实体主题:

/**
 *
 * @ORM\Table()
 * @ORM\HasLifecycleCallbacks()
 */
class Subject
{

    //... Some fields

    /**
     * @ORM\OneToMany(targetEntity="Subject", mappedBy="mark", cascade={"persist", "remove"})
     */
    private $subjects;


    private function calculateMarks()
    {
        //... Do something

        // return array with (abilities => marks);
    }

    /**
     * @ORM\PrePersist()
     */
    public function prePersist(){
        $now = new \DateTime();
        $this->setCreatedAt( $now );
        $this->setModifiedAt( $now );
    }

    /**
     * @ORM\PreUpdate()
     */
    public function preUpdate(){
        $this->setModifiedAt( new \DateTime() );
        $this->setUpdated(true);
    }

    /**
     * @ORM\PreFlush()
     */
    public function preFlush(){
        $marks = calculateMarks();

        foreach($marks as $ability => $score){
            $mark = new Mark();
            $mark->setSubject( $this );
            $this->addMark( $score );
            $mark->setAbility( $ability );
        }
    }
}

和Mark类:

class Mark{

    // Many fields

    /**
     * @ORM\ManyToOne(targetEntity="Subject", inversedBy="subjects")
     * @ORM\JoinColumn(name="subject_id", referencedColumnName="id")
     */
    private $subject;
}

我的问题是我计算并在preFlush事件中创建了Marks(这样做是因为在官方文档中说的是关于preUpdate事件:“在此事件中永远不允许更新实体的关联,因为Doctrine不能保证在刷新操作的这一点上正确处理参照完整性“)。当我保存一个主题时,一切正常,但是当我在Web服务中同时保存多个主题时,一些标记会多次存储在数据库中。

以下网络服务行动:

public function setSubjects(Request $request)
{
    //... Do something

    $subjects         = $request["Subjects"];

    foreach($subjects as $s){
        $em = $this->getDoctrine()->getManager();

        //... Do something

        $em->persist($s);
        $em->flush();
    }

    return new JsonResponse($response);
}

有没有人知道如何在preFlush事件中避免这种行为?

提前致谢。

1 个答案:

答案 0 :(得分:0)

我总是尽量避免使用LifecycleCallbacks,除非它很简单,而且我只是在同一个实体中更改属性。

解决你的问题我会在实体中创建一个函数calculateMarks()并调整我的循环就像

$em = $this->getDoctrine()->getManager();
foreach($subjects as $s){
    //... Do something
    $s->calculateMarks();
    $em->persist($s);
}
$em->flush();

注意

避免$em = $this->getDoctrine()->getManager();&循环中的$em->flush();