在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();
但是,假设您的用户模型与许多其他模型有hasMany
关系,例如Post
模型:
Post:
id
name
body
user_id
因此,在这种情况下,您希望使用在Users表中播种的 实际 用户为您的帖子加密。这似乎没有明确讨论过,但我确实在Laravel文档中找到了以下内容:
$users = factory(App\User::class, 3)
->create()
->each(function($u) {
$u->posts()->save(factory(App\Post::class)->make());
});
因此,在您的用户工厂中,您为每个创建的用户创建X个帖子。但是,在一个大型应用程序中,可能有50-75个模型与用户模型共享关系,您的用户播种器实际上最终会将整个数据库与其所有关系一起播种。
我的问题是:这是处理此问题的最佳方法吗?我能想到的唯一另一件事是首先播种用户(没有播种任何关系),然后在播种其他模型时根据需要从数据库中随机抽取用户。但是,如果它们需要是唯一的,您必须跟踪哪些用户已被使用。此外,这似乎会为播种过程增加许多额外的查询 - 批量。
答案 0 :(得分:25)
您也可以使用saveMany。例如:
factory(User::class, 10)->create()->each(function ($user) {
$user->posts()->saveMany(factory(Posts::class, 5)->make());
});
答案 1 :(得分:8)
您可以使用ModelFactory中的闭包执行此操作,如here所述。
此解决方案也适用于播种机。
$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]);
});
注意:此方法不会在数据库中创建不需要的条目,而是在创建关联记录之前分配传递的属性。
答案 2 :(得分:6)
就我个人而言,我认为管理这些关系的一个Seeder类比分离的播种器类更好,因为你在一个地方拥有所有的逻辑,所以在一个看起来你可以看到发生了什么。 (任何了解更好方法的人:请分享):)
解决方案可能是:一个DatabaseSeeder和类中的私有方法,以保持'运行'方法有点清洁。我在下面有这个例子,它有一个User,Link,LinkUser(多对多)和一个Note(多对一)。
对于多对多关系,我首先创建所有链接,然后获取插入的ID。 (因为id是auto-inc我认为id可以更容易获取(获得最大值),但在这个例子中并不重要)。然后创建用户,并为每个用户附加一些随机链接(多对多)。它还为每个用户创建随机笔记(多对一示例)。它使用'工厂'方法
如果您更换了'链接'为你的'发布'这应该工作。 (您可以删除'注意'部分然后......)
(还有一种方法可以确保您拥有1位拥有自己登录凭据的有效用户。)
<?php
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
// Create random links
factory(App\Link::class, 100)->create();
// Fetch the link ids
$link_ids = App\Link::all('id')->pluck('id')->toArray();
// Create random users
factory(App\User::class, 50)->create()->each(function ($user) use ($link_ids) {
// Example: Many-to-many relations
$this->attachRandomLinksToUser($user->id, $link_ids);
// Example: Many-to-one relations
$this->createNotesForUserId( $user->id );
});
// Make sure you have a user to login with (your own email, name and password)
$this->updateCredentialsForTestLogin('john@doe.com', 'John Doe', 'my-password');
}
/**
* @param $user_id
* @param $link_ids
* @return void
*/
private function attachRandomLinksToUser($user_id, $link_ids)
{
$amount = random_int( 0, count($link_ids) ); // The amount of links for this user
echo "Attach " . $amount . " link(s) to user " . $user_id . "\n";
if($amount > 0) {
$keys = (array)array_rand($link_ids, $amount); // Random links
foreach($keys as $key) {
DB::table('link_user')->insert([
'link_id' => $link_ids[$key],
'user_id' => $user_id,
]);
}
}
}
/**
* @param $user_id
* @return void
*/
private function createNotesForUserId($user_id)
{
$amount = random_int(10, 50);
factory(App\Note::class, $amount)->create([
'user_id' => $user_id
]);
}
/**
* @param $email
* @param $name
* @param $password
* @return void
*/
private function updateCredentialsForTestLogin($email, $name, $password)
{
$user = App\User::where('email', $email)->first();
if(!$user) {
$user = App\User::find(1);
}
$user->name = $name;
$user->email = $email;
$user->password = bcrypt($password); // Or whatever you use for password encryption
$user->save();
}
}
答案 3 :(得分:5)
$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' => factory(App\User::class)->create()->id,
];
});
现在,如果您执行此操作factory(App\Post::class, 4)->create()
,它将创建4个不同的帖子,并且在此过程中还会创建4个不同的用户。
如果您希望所有帖子都使用相同的用户,我通常会这样做:
$user = factory(App\User::class)->create();
$posts = factory(App\Posts::class, 40)->create(['user_id' => $user->id]);
答案 4 :(得分:0)
我想分享我为很多用户插入很多帖子所采用的方法:`
namespace mars
{
namespace
{
int test = 0;
}
}
int main()
{
// Adding a watch on test does not work.
mars::test++;
return 0;
}
`
这种解决方法在我整天寻找种子关系的方法之后为我工作
答案 5 :(得分:0)
这在laravel v8中对我有用
for ($i=0; $i<=2; $i++) {
$user = \App\Models\User::factory(1)->create()->first();
$product = \App\Models\Product::factory(1)->create(['user_id' => $user->id])->first();
}