使用模型工厂、一对一和一对多关系定义 Laravel 外键,而无需创建不必要的模型
Defining Laravel foreign keys with Model Factories, One to One & One to Many Relationships without creating unnecessary models
最近我一直在尝试使用 Laravel 通过 Model Factories 和 Faker 播种来播种我的数据库。
对于简单的模式,让它工作起来轻而易举:)。但是,在处理涉及 外键和 table 关系的复杂数据库模式时,我遇到了几个问题:
- 一对一
- 一对多
- 多对多
...就像link中描述的那样:
Laravel 5.1 foreign keys in model factory.
在本主题中,official documentation 建议 运行 数据库种子如下:
public function run()
{
factory(App\User::class, 50)->create()->each(function ($u) {
$u->posts()->save(factory(App\Post::class)->make());
});
}
...但是这个解决方案有一个问题:当处理许多数据库 tables 和 运行ning 许多种子(它们之间有很多关系)时,[= =28=]使用这种方法创建许多不必要的模型。例如,如果我们在上述示例之一之前有 运行 PostsTableSeeder.php,那么所有这些帖子都不会 link 发送给用户,并且永远不会用于测试和开发...
所以寻找一种方法来处理这种情况,我想出了一个适合我的功能解决方案,避免了不必要地创建那些 'orphan' 模型...
并且想分享给大家,所以在回答中说明了:).
所以这是我的解决方案:
示例涉及:
- 用户和个人资料(用于说明一对一关系)
用户和帖子(用于说明一对多关系)
// ONE TO ONE relationship (with Users already created)
$factory->define(App\Profile::class, function (Faker\Generator $faker) {
return [
'user_id' => $faker->unique()->numberBetween(1, App\User::count()),
// Rest of attributes...
];
});
// ONE TO MANY relationship (with Users already created)
$factory->define(App\Posts::class, function (Faker\Generator $faker) {
$users = App\User::pluck('id')->toArray();
return [
'user_id' => $faker->randomElement($users),
// Rest of attributes...
];
});
这是建立关系的解决方案,比分配随机用户要好得多,尤其是当您需要向该模型发送额外信息时。
$factory->define(App\Post::class, function (Faker\Generator $faker) {
$user = factory('App\Models\User')->create(['email' => 'email@test.com',]);
// do your relationships here (...)
return [
'user_id' => $user->id,
'title' => $faker->sentence,
'body' => $faker->paragraph,
];
}
我还看到了另一个使用匿名函数的例子
$factory->define(App\Post::class, function (Faker\Generator $faker) {
return [
'user_id' => function () {
return factory(App\User::class)->create()->id;
},
'title' => $faker->sentence,
'body' => $faker->paragraph,
];
}
来源:https://laracasts.com/series/laravel-from-scratch-2017/episodes/22
这就是我在工厂的 FK 中使用的
return [
'user_id' => $this->faker->randomElement(User::pluck('id')),
...
];
注意:确保您的工厂运行顺序正确
最近我一直在尝试使用 Laravel 通过 Model Factories 和 Faker 播种来播种我的数据库。
对于简单的模式,让它工作起来轻而易举:)。但是,在处理涉及 外键和 table 关系的复杂数据库模式时,我遇到了几个问题:
- 一对一
- 一对多
- 多对多
...就像link中描述的那样: Laravel 5.1 foreign keys in model factory.
在本主题中,official documentation 建议 运行 数据库种子如下:
public function run()
{
factory(App\User::class, 50)->create()->each(function ($u) {
$u->posts()->save(factory(App\Post::class)->make());
});
}
...但是这个解决方案有一个问题:当处理许多数据库 tables 和 运行ning 许多种子(它们之间有很多关系)时,[= =28=]使用这种方法创建许多不必要的模型。例如,如果我们在上述示例之一之前有 运行 PostsTableSeeder.php,那么所有这些帖子都不会 link 发送给用户,并且永远不会用于测试和开发...
所以寻找一种方法来处理这种情况,我想出了一个适合我的功能解决方案,避免了不必要地创建那些 'orphan' 模型...
并且想分享给大家,所以在回答中说明了:).
所以这是我的解决方案:
示例涉及:
- 用户和个人资料(用于说明一对一关系)
用户和帖子(用于说明一对多关系)
// ONE TO ONE relationship (with Users already created) $factory->define(App\Profile::class, function (Faker\Generator $faker) { return [ 'user_id' => $faker->unique()->numberBetween(1, App\User::count()), // Rest of attributes... ]; }); // ONE TO MANY relationship (with Users already created) $factory->define(App\Posts::class, function (Faker\Generator $faker) { $users = App\User::pluck('id')->toArray(); return [ 'user_id' => $faker->randomElement($users), // Rest of attributes... ]; });
这是建立关系的解决方案,比分配随机用户要好得多,尤其是当您需要向该模型发送额外信息时。
$factory->define(App\Post::class, function (Faker\Generator $faker) {
$user = factory('App\Models\User')->create(['email' => 'email@test.com',]);
// do your relationships here (...)
return [
'user_id' => $user->id,
'title' => $faker->sentence,
'body' => $faker->paragraph,
];
}
我还看到了另一个使用匿名函数的例子
$factory->define(App\Post::class, function (Faker\Generator $faker) {
return [
'user_id' => function () {
return factory(App\User::class)->create()->id;
},
'title' => $faker->sentence,
'body' => $faker->paragraph,
];
}
来源:https://laracasts.com/series/laravel-from-scratch-2017/episodes/22
这就是我在工厂的 FK 中使用的
return [
'user_id' => $this->faker->randomElement(User::pluck('id')),
...
];
注意:确保您的工厂运行顺序正确