如果数据不存在,Laravel插入种子数据。

3
有没有办法在运行laravel seed时仅在记录不存在的情况下插入记录?
我当前的laravel种子文件如下:
DB::table('users')->insert([
                //Global Admin
                [
                    'member_id' => 11111111,
                    'firstname' => 'Joe',
                    'lastname' => 'Bloggs'
                ], 
                [
                    'member_id' => 22222222,
                    'firstname' => 'Jim',
                    'lastname' => 'Bloggs'
                ], 

            ]);

非常标准!

我需要将每个插入语句都包裹在try catch块中吗?就像这样:

try {
   DB::table('users')->insert(['member_id' => 11111111, 'firstname' => 'Joe', 'lastname' => 'Bloggs']);
} catch(Exception $e){
  //Die silently
}
try {
   DB::table('users')->insert(['member_id' => 22222222, 'firstname' => 'Jim', 'lastname' => 'Bloggs']);
} catch(Exception $e){
  //Die silently
}

以后我可能想在同一个种子中添加额外的行,而不必编写新的种子,并重新运行php artisan db:seed仅添加我的新行。

这是否可行?

5个回答

7

您可以使用Eloquent的firstOrCreate方法实现此目的。

firstOrCreate方法将尝试使用给定的列/值对定位数据库记录。如果在数据库中找不到模型,则将使用第一个参数中的属性和可选的第二个参数中的属性插入记录。

因此,如果您通过member_id来标识用户,则可以像这样操作:

    User::firstOrCreate(
        ['member_id' => 11111111],
        [
            'firstname' => 'anakin',
            'lastname' => 'skywalker',
            'password' => Hash::make('4nak1n')
        ]
    );

如果您想通过“member_id”、“firstname”和“lastname”字段定位记录,可以使用以下方式:
    User::firstOrCreate(
        [
            'member_id' => 11111111,
            'firstname' => 'anakin',
            'lastname' => 'skywalker'
        ],
        [
            'password' => Hash::make('4nak1n'),
        ]
    );

3

种子数据只应该用于测试。

为什么不直接执行php artisan migrate:fresh --seed

这将刷新您的数据库(删除表),然后重新运行所有迁移,最后再次填充数据库。

在生产环境中永远不应该使用种子数据。

只需将新数据添加到您的种子文件中,运行migrate:fresh并重新填充即可 :)

最初的回答

我正在使用seeder将默认数据添加到系统中,这样当我第一次将其推送到生产环境时,就不必担心手动添加大量数据。此外,如果我推出一个带有新迁移和默认数据的新功能,则无法在实时数据库上运行php artisan db:seed,因为它会抛出默认数据已存在的错误! - S_R
3
在这种情况下,您需要创建单独的种子文件,并根据文档调用php artisan db:seed --class=UsersTableSeeder来运行该种子文件。请注意,您需要保持原文的意思,但需要使翻译更加通俗易懂,不包含任何额外的解释或信息。 - stokoe0990
1
注意,Laravel开发人员不推荐在生产环境中使用种子填充(seeding),而是通过--force标志强制执行。 - Ben Sholdice

3
根据 stokoe0990 的说法,生产环境下不建议运行种子数据生成器。 Laravel Seeder 的编写旨在生成测试数据。根据文档的描述:"Laravel 包含一种简单的方法,使用种子类向数据库中填充测试数据。"。
然而,如果您需要满足自己的需求,则唯一的方法是将逻辑构建到您的种子文件中。
$users = array(
    ['member_id' => 11111111,'firstname' => 'Joe','lastname' => 'Bloggs'], 
    ['member_id' => 22222222,'firstname' => 'Jim','lastname' => 'Bloggs']
);

foreach ($users as $user) {
  if (\App\User::find($user['id'])) {
    DB::table('users')->insert($user);
  }
}

我认为你是对的,不幸的是这似乎是最合乎逻辑的方式! - S_R
1
我想再次强调,在生产环境中运行种子填充程序是强烈不建议的。 - stokoe0990
2
我想指出有时需要将应用程序部署到每个客户端的新环境中,在这种情况下,您可能希望有一些数据作为起点。我经常在表的初始迁移中嵌入seeder以在生产环境中填充一些数据(仅限第一次部署)。这只是值得思考的一些事情。;) - Ivan Carosati

1
您可以通过使用Eloquent的updateOrInsert()方法来实现:
DB::table('users')->updateOrInsert('your_data');

阅读更多关于它的内容在这里


1
我在考虑使用这种方法,但是如果用户在以后更改了密码或数据,它不会将其更新回到种子中的数据吗? - S_R

1
我最推荐的方法是在迁移时截断(或删除)表中的所有数据。可以尝试类似以下的代码:
//data in the table
DB::table('users')->delete(); //or use model like this: User::truncate();

DB::table('users')->insert([
                //Global Admin
                [
                    'member_id' => 11111111,
                    'firstname' => 'Joe',
                    'lastname' => 'Bloggs'
                ], 
                [
                    'member_id' => 22222222,
                    'firstname' => 'Jim',
                    'lastname' => 'Bloggs'
                ], 
            ]);

这样,当你运行php artisan db:seed时就不会有重复了。


这种情况下,如果现有数据被引用了 restrict ondelete 约束,则无法正常工作。 - Masaba James Moses

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接