Eloquent 的 createMany 方法是否保留输入数组顺序?

Does Eloquent's createMany method preserves the input array order?

我有 Choice 型号 belongTo Question 型号 belongTo Quiz 型号。确切地说:

上述关系在 Request 中很受欢迎(如下所示)。


我需要在三个事务中完成所有插入操作。

我有以下两个成功的交易。

DB::transaction(function () use ($request) {
    $quiz = Quiz::create(['start_at' => $request->start_at, 'duration' => $request->duration]);
    $questions = $quiz->questions()->createMany($request->questions);
// ...

现在我需要确认 $questions 将类似于 $request->questions 在任何情况下都按照数据的顺序,依靠这一事实并将id从返回的集合映射到Request的选择作为foreign ids 并再做一次批量插入。

// ...
    $choices = [];
    foreach ($request->questions as $i => $question_data) {
        foreach ($question_data['choices'] as $j => $choice_content) {
            $choices[] = [
                'question_id' => $questions[$i - 1]->id, // Append foreign id
                'content' => $choice_content,
                'choice_number' => $j,
                'is_correct' => $j == $question_data['is_correct'],
                'created_at' => date('Y-m-d H:i:s'),
            ];
        }
    }
    Choice::insert($choices);
});

{
    "start_at": "2022-07-17T19:54",
    "duration": "191",
    "questions": {
        "1": {
            "content": "Sed asperiores eaque voluptatem id saepe.",
            "choices": {
                "1": "Ad quia impedit libero voluptatem qui.",
                "2": "Voluptates quis consequuntur natus illum laborum tempore.",
                "3": "Corrupti dolorum optio quam qui.",
                "4": "Numquam quidem voluptatem nisi."
            },
            "is_correct": "4"
        },
        "2": {
            "content": "Illum ut tempora.",
            "choices": {
                "1": "Consequatur minima tempora qui amet.",
                "2": "Voluptate sint sapiente illum delectus possimus enim.",
                "3": "A magni aut aperiam aliquam laboriosam.",
                "4": "Faustino MacGyver"
            },
            "is_correct": "4"
        },
        "3": {
            // ...
        },
        "4": {
            // ...
        }
    }
}

获取生成的SQL。如果末尾附近有一个 ORDER BY 子句,那么顺序是可预测的。如果没有 ORDER BY 子句,数据库可以自由地以任何顺序传送结果。

Laravel 的 createMany 在您提供的数组上执行 foreach 并按照您传入的顺序执行 returns 它应该保留命令。 这是来源:

   public function createMany(iterable $records)
    {
        $instances = $this->related->newCollection();

        foreach ($records as $record) {
            $instances->push($this->create($record));
        }

        return $instances;
    }

这不一定适用于该数据的后续查询。这取决于数据库如何决定在没有 order by 子句的情况下对其进行排序。

话虽如此,您可以通过在创建每个问题时设置选项来避免整个问题。由于你们有关系,您可以允许 Laravel 弄清楚如何设置正确的 ID。

foreach ($request->questions as $question_data) {

    $question = $quiz->questions()->create([
        // question data here
    ]);

    foreach ($question_data['choices'] as $j => $choice_content) {

        $question->choices()->create(
            [
                // choice data here
            ]
        );
      }
    }