Laravel 8自关联Contest模型数据填充报错解决方法
解决Laravel填充自关联模型时
array_rand()空数组报错的问题 这个错误的原因很直观:当你执行填充器时,第一次运行的瞬间Contest表是空的,你调用\App\Models\Contest::all()->pluck('id')->toArray()得到的是空数组,而array_rand()函数无法处理空数组,所以抛出了ErrorException array_rand(): Array is empty。
你的原代码核心问题是:试图一次性创建10条数据,但在创建开始前就去获取Contest的id列表——这时候数据库里还没有任何数据,自然是空数组。
下面给你两种实用的解决方案:
方案一:先创建根竞赛,再生成子竞赛
先创建一批无父级的根竞赛,再基于这些根竞赛的id来分配子竞赛的父级,确保始终有可用的id数组:
public function run() { // 先创建5个无父级的根竞赛 $rootContests = \App\Models\Contest::factory(5)->create(['contest_id' => null]); // 再创建10个子竞赛,从根竞赛中随机选取父级id \App\Models\Contest::factory(10)->create([ // 使用闭包,每个模型创建时动态获取随机父级id 'contest_id' => fn () => $rootContests->random()->id ]); }
方案二:混合创建根节点与子节点
如果你希望既有根节点(无父级)又有子节点,还可以随机控制是否分配父级,同时确保第一次创建时有初始数据存在:
public function run() { // 先创建第一个根竞赛,确保数据库有初始数据 \App\Models\Contest::factory()->create(['contest_id' => null]); // 循环创建14条数据,随机决定是否设置父级 for ($i = 0; $i < 14; $i++) { \App\Models\Contest::factory()->create([ 'contest_id' => rand(0, 1) ? \App\Models\Contest::all()->random()->id : null ]); } }
关键注意点
- 避免在批量创建时直接用
array_rand(\App\Models\Contest::all()->pluck('id')->toArray()),因为这个值是在所有模型开始创建前就计算好的,此时数据库还是空的。 - 使用Laravel工厂的闭包(
fn () => ...)可以让每个模型在创建时动态计算字段值,这样前面创建的模型已经存入数据库,后续就能获取到有效的id了。
内容的提问来源于stack exchange,提问作者Owen Kelvin
相关产品推荐
相关产品推荐

