一次性在Laravel 5中种植多行数据

66

我目前正在尝试为我的用户表生成数据。如果我使用下面这个方法并且要生成两行数据,它会失败。但是如果我只是使用单个数组而不是 $users 数组内的两个数组来创建一些虚假数据,它就可以正常工作。

我错在哪里了?有什么正确的方法吗?

class UserTableSeeder extends Seeder {

    public function run()
    {
        DB::table('users')->delete();

        $users = [
            ['id' => 1, 'name' => 'Stephan de Vries', 'username' => 'stephan', 'email' => 'stephan-v@gmail.com', 'password' => bcrypt('carrotz124')],
            ['id' => 2, 'name' => 'John doe', 'username' => 'johnny', 'email' => 'johndoe@gmail.com', 'password' => bcrypt('carrotz1243')],
        ];

        User::create($users);
    }

}

8个回答

83

如果您必须使用该模型,则需要使用循环:

foreach($users as $user){
    User::create($user);
}
否则您可以使用DB :: table()insert:
DB::table('users')->insert($users);

实际上,您也可以在模型上调用 insert() 方法(生成的查询相同)

User::insert($users);

注意,如果您选择使用insert方法,则会失去特殊的Eloquent功能,例如时间戳和模型事件。


1
最近有改动吗?我有一点模糊的记忆,好像以前可以做到OP尝试的那样。 - Joel Hinz
1
@JoelHinz 不是真的。据我所知,这从来就不可能发生过。有人曾经提出过这个问题(https://github.com/laravel/framework/issues/1295),但该请求被拒绝了。 - lukasgeiter
谢谢,它运行得很好。可惜我在官方文档中找不到类似的回溯方法。 - Stephan-v
好的,可能是我的记忆出了问题。 :) - Joel Hinz
@lukasgeiter,你在回答中使用foreach的第一部分代码非常糟糕。->create()方法会立即触发插入命令。更好的方法是使用->make()方法生成数据,然后只使用一个查询来插入生成的数据。 - lewis4u

56

这适用于 Laravel ^5

<?php

use Illuminate\Database\Seeder;

class UsersTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */

    public function run()
    {
        // check if table users is empty
        if(DB::table('users')->count() == 0){

            DB::table('users')->insert([

                [
                    'name' => 'Administrator',
                    'email' => 'admin@app.com',
                    'password' => bcrypt('password'),
                    'created_at' => date('Y-m-d H:i:s'),
                    'updated_at' => date('Y-m-d H:i:s'),
                ],
                [
                    'name' => 'Agency',
                    'email' => 'agency@app.com',
                    'password' => bcrypt('password'),
                    'created_at' => date('Y-m-d H:i:s'),
                    'updated_at' => date('Y-m-d H:i:s'),
                ],
                [
                    'name' => 'End',
                    'email' => 'endcustomer@app.com',
                    'password' => bcrypt('password'),
                    'created_at' => date('Y-m-d H:i:s'),
                    'updated_at' => date('Y-m-d H:i:s'),
                ]

            ]);
            
        } else { echo "\e[31mTable is not empty, therefore NOT "; }

    }
}

9
这个命令似乎只插入了第一行,并且没有报错。 - gray_15
@gray_15 不是对我说的! - giovannipds
如果我或者将来遇到同样错误的人来到这里,重要的是要指定每个插入的列名(我没有这样做,所以它给了我一个错误)。 - giovannipds
@gray_15 我也有相同的问题,但是如果我将用户数组移出插入语句,直接执行insert($users)就可以正常工作。 - Egnaro
4
直接传递数组或先将其放入变量中不应有区别。但如果您直接这样做,请不要忘记添加实际的数组括号。例如,[a => 1, b=>2],[a=>3, b=>4] 是不行的。确保您输入 [[a => 1, b=>2], [a =>3, b =>4]],这样您就可以传递一组记录的数组。否则,您将把除第一个之外的所有内容作为参数传递给 insert。 - Ivo Jansch
我在Laravel 8中遇到了同样的问题,但是我的问题通过这个答案得到了解决。问题在于:我将许多数组作为参数传递给insert方法,而我应该传递一个数组的数组。只需添加第一个和最后一个括号即可完成。 - César Rodriguez

11

create()是用来存储单个记录的。如果要存储多条记录,应使用insert() 而不是 create()

所以代码将像这样:

class UserTableSeeder extends Seeder {

  public function run()
  {
    DB::table('users')->delete();

    $users = [
        ['id' => 1, 'name' => 'Stephan de Vries', 'username' => 'stephan', 'email' => 'stephan-v@gmail.com', 'password' => bcrypt('carrotz124')],
        ['id' => 2, 'name' => 'John doe', 'username' => 'johnny', 'email' => 'johndoe@gmail.com', 'password' => bcrypt('carrotz1243')],
    ];

    User::insert($users);
  }

}

提示:insert()函数不会存储时间戳,即created_byupdated_by字段。


9
public function run()
{
    //
    for ($i=0; $i < 1000; $i++) { 
         DB::table('seo_contents')->insert([
            'title' => str_random(10),
            'content' => str_random(100),
            'created_at'=>date('Y-m-d H:i:s'),
            'updated_at'=>date('Y-m-d H:i:s'),

        ]);
    }

}

不要在种子文件中使用foreach或for循环。如果数据量很大,这会对性能产生巨大影响。每次插入都会生成一个查询,而不是在一个查询中完成所有插入操作。 - lewis4u
请您详细说明虚拟数据生成过程对foreach或for循环的影响,是否有其他替代方案? - Simple Test
这只是有关命中数据库的查询量的问题... 使用上面的代码,您将向数据库发出1000个插入查询... 更好的方法是首先创建数据(在 RAM 中)使用 foreach,然后使用一个单独的查询来存储数据,例如 DB::table('seo_contents')->insert($data); 其中 $data 是生成行的数组。 - lewis4u

5

使用 truncate

<?php

use Illuminate\Database\Seeder;
use App\User;

class UsersTableSeeder extends Seeder
{
     /**
     * Run the database seeds.
     *
     * @return void
     */

  public function run()
    {

      User::truncate();

        $users =  [
            [
              'name' => 'Super Admin',
              'email' => 'superadmin@gmail.com',
              'password' => '123456',
            ],
            [
              'name' => 'Account Admin',
              'email' => 'accountadmin@gmail.com',
              'password' => '13456',
            ],
            [
              'name' => 'Project Admin',
              'email' => 'projectadmin@gmail.com',
              'password' => '13456',
            ],
            [
              'name' => 'Client Admin',
              'email' => 'clientadmin@gmail.com',
              'password' => '13456',
            ]
          ];

          User::create($users);

    }
}

这实际上也适用于 Laravel 10,并且我发现这是使用 php artisan db:seed 创建多个记录的最简单解决方案。 - shaz3e

3

如果有人在使用中遇到了问题,我从 Laravel 5 开始一直使用以下方法,并确认它在 Laravel 7+ 中仍然有效...

class UserTableSeeder extends Seeder {

public function run()
{
    \DB::table('users')->delete();

    \DB::table('users')->insert(array (
        0 => 
          array (
                 'id' => 1,
                 'name' => 'Stephan de Vries',
                 'username' => 'stephan',
                 'email' => 'stephan-v@gmail.com',
                 'password' => bcrypt('carrotz124'
         ),
        1 => 
          array (
                 'id' => 2,
                 'name' => 'John doe',
                 'username' => 'johnny',
                 'email' => 'johndoe@gmail.com',
                 'password' => bcrypt('carrotz1243'
         ),
     ));

}}

0

我是这样做的,每次运行种子时插入新记录并更新以前的记录。

$languages = [
        ['id' => 1, 'language_name' => 'English', 'language_code' => 'en'],
        ['id' => 2, 'language_name' => 'Spanish', 'language_code' => 'es'],
        ['id' => 3, 'language_name' => 'French', 'language_code' => 'fr'],
        ['id' => 4, 'language_name' => 'German', 'language_code' => 'de'],
        ['id' => 5, 'language_name' => 'Swahili', 'language_code' => 'sw']
    ];

    foreach ($languages as $language) {
        Language::updateOrCreate(['id' => $language['id']], $language);
    }

0
如果您想要插入随机数据来进行分期,可以使用for循环。
for ($i = 0; $i <= 29; $i++) {
            DB::table('userdata')->insert([
                'uname' => Str::random(10),
                'upassword' => Str::random(10)
            ]);

            DB::table('testtable2')->insert([
                'name' => Str::random(10),
                'number' => random_int(100, 9999)
            ]);
     }

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