Laravel - 播种关系

2022-08-30 13:31:43

在Laravel中,数据库种子设定通常通过模型工厂完成。因此,您可以使用 Faker 数据为模型定义蓝图,并说明您需要多少个实例:

$factory->define(App\User::class, function (Faker\Generator $faker) {
    return [
        'name' => $faker->name,
        'email' => $faker->email,
        'password' => bcrypt(str_random(10)),
        'remember_token' => str_random(10),
    ];
});

$user = factory(App\User::class, 50)->create();

但是,假设您的用户模型与许多其他模型有关系,例如模型:hasManyPost

Post:
   id
   name
   body
   user_id

因此,在这种情况下,您希望使用在“用户”表中播种的实际用户来设定“帖子”表的种子。这似乎没有被明确讨论,但我确实在Laravel文档中发现了以下内容:

$users = factory(App\User::class, 3)
    ->create()
    ->each(function($u) {
         $u->posts()->save(factory(App\Post::class)->make());
    });

因此,在用户工厂中,您可以为创建的每个用户创建 X 个帖子。但是,在可能有 50 - 75 个模型与用户模型共享关系的大型应用程序中,您的用户播种器基本上最终会在整个数据库中播种所有关系。

我的问题是:这是处理这个问题的最佳方式吗?我能想到的唯一另一件事是首先为用户设定种子(不为任何关系设定种子),然后在为其他模型设定种子时根据需要从数据库中提取随机用户。但是,在它们需要唯一的情况下,您必须跟踪使用了哪些用户。此外,这似乎会给种子设定过程增加很多额外的查询批量。


答案 1

您也可以使用 saveMany。例如:

factory(User::class, 10)->create()->each(function ($user) {
    $user->posts()->saveMany(factory(Posts::class, 5)->make());
});

答案 2

您可以使用模型工厂中的闭包来执行此操作,如此所述。

该解决方案还可以与播种机干净优雅地配合使用。

$factory->define(App\User::class, function (Faker\Generator $faker) {
    return [
        'name' => $faker->name,
        'email' => $faker->email,
        'password' => bcrypt(str_random(10)),
        'remember_token' => str_random(10),
    ];
});

$factory->define(App\Post::class, function (Faker\Generator $faker) {
    return [
        'name' => $faker->name,
        'body' => $faker->paragraph(1),
        'user_id' => function() {
            return factory(App\User::class)->create()->id;
        },
    ];
});

对于您的播种机,请使用如下所示的简单方法:

//create 10 users
factory(User::class, 10)->create()->each(function ($user) {
    //create 5 posts for each user
    factory(Post::class, 5)->create(['user_id'=>$user->id]);
});

注意:此方法不会在数据库中创建不需要的条目,而是在创建关联记录之前分配传递的属性。


推荐