Make Doctrine以原始顺序添加实体

时间:2015-09-24 16:41:48

标签: php symfony doctrine-orm

我有以下代码:

$em = $this->getDoctrine()->getManager();

$evaluation->getQuestions()->clear();

foreach ($questions_data as $data) {
    $id = (int) $data['id'];        

    if ($id > 0) {
        $question = $em->getRepository('MyBundle:Question')->find($id);

        if ($question)
            $evaluation->getQuestions()->add($question);
    }
}

$em->persist($evaluation);
$em->flush();

以下是$questions_data - array(['id' => 2], ['id' => 1], ['id' => 3]) 以下是教义如何将问题持续存在于数据库中:
enter image description here

那么,如何让学说不对问题进行排序呢? Evaluation实体与ManyToMany实体有Question关系,因此ORDER BY无法提供帮助,因为evaluations_questions表自动创建了表Doctrine,没有字段id

3 个答案:

答案 0 :(得分:5)

当您在Doctrine中刷新新持久化的项目时,Doctrine必须使用内部函数getCommitOrder确定将它们提交到数据库的顺序。该函数的目的是确保在提交对象之前提交对象的依赖性。这样做是为了符合可能设置的任何外键约束。正如您所观察到的那样,对数据进行排序的结果就是您失去了精确调整项目提交顺序的能力 - 这不一定是坏事

在SQL中,您可以通过ORDER BY发出查询来查看结果的唯一方法。如果您选择不指定排序方法,则不能指望结果以任何特定顺序返回。 PostgreSQL docs解释了这个:

  

如果未选择排序,则将以未指定的顺序返回行。在这种情况下,实际订单将取决于扫描和加入计划类型以及磁盘上的订单,但不能依赖

换句话说,内容存储在数据库中的顺序并不重要。

在您的问题中,问题对用户的显示顺序是个问题。您不能允许问题在评估中随机出现 - 它们必须遵循预设的顺序。 Frankbeen在评论中对此进行了讨论,但最好的解决方案是在Evaluation上添加一个新字段,以适当的顺序存储Questions $em = $this->getDoctrine()->getManager(); $evaluation->getQuestions()->clear(); foreach ($questions_data as $data) { $id = (int) $data['id']; if ($id > 0) { $question = $em->getRepository('MyBundle:Question')->find($id); if ($question) { $evaluation->getQuestions()->add($question); $em->persist($evaluation); $em->flush(); } } } 。然后,当您向用户提供评估时,可以阅读订单。

如果您绝对必须按照数据库中的特定顺序对它们进行排序,那么您应该能够在持久化时单独刷新新对象,而不是将它们安排为一起刷新。

TableA {

String aId;

@OneToMany(fetch = FetchType.EAGER)
List<TableB> tableB;

}

TableB {
String aId;
String bId;

@ManyToOne(fetch = FetchType.EAGER)
TableC tableC;

}

TableC {
String cId;
String name;
}

请注意,这将需要更长的时间才能完成,对您的问题来说是一个非常糟糕的解决方案。

答案 1 :(得分:1)

新记录始终存储在表的末尾。如果您想以自然顺序(通过id)获得问题,那么您应该使用ORDER BY。我猜评价实体与问题实体有一个OneToMany关系。

在这种情况下,您可以在Evalutation实体的$ questions属性上方添加可选注释:

/**
 * @ORM\OneToMany(targetEntity="Question")
 * @ORM\OrderBy({"id" = "ASC"})
 */
private $questions;

答案 2 :(得分:0)

EntityManagerInterface具有事务支持,我建议对所有多语句操作使用该功能。这将允许您创建多个语句,并一次按顺序提交它们。每条语句将按照添加的顺序执行,如果一条语句失败,则完全不会对数据库进行任何更改。

话虽这么说,所有数据库实现都可能未按添加顺序存储数据,因此,如果期望按特定顺序返回数据,则应始终使用ORDER BY进行显式查询,如另一个回复。

如果遇到ID不明的问题,说要中止操作。可以使用以下类似的方法很容易地完成此操作:

function storeQuestions($questions_data): bool
{
    $em = $this->getDoctrine()->getManager();
    $em->beginTransaction();

    $evaluation->getQuestions()->clear();

    foreach ($questions_data as $data) {
        $id = (int) $data['id'];        

        if ($id > 0) {
            $question = $em->getRepository('MyBundle:Question')->find($id);

            if ($question) {
                $evaluation->getQuestions()->add($question);
                $em->persist($evaluation);
            } else {
                $em->rollback();
                return false;
            }
        }
    }

    $em->commit();
    $em->flush();

    return true; // Success
}