【问题标题】:Populating a database in a Laravel migration file在 Laravel 迁移文件中填充数据库
【发布时间】:2012-09-26 00:17:00
【问题描述】:

我刚刚学习 Laravel,并且有一个工作迁移文件创建一个用户表。作为迁移的一部分,我正在尝试填充用户记录:

public function up()
{
    Schema::create('users', function($table){

        $table->increments('id');
        $table->string('email', 255);
        $table->string('password', 64);
        $table->boolean('verified');
        $table->string('token', 255);
        $table->timestamps();

        DB::table('users')->insert(
            array(
                'email' => 'name@domain.com',
                'verified' => true
            )
        );

    });
}

但是在运行php artisan migrate 时出现以下错误:

SQLSTATE[42S02]: Base table or view not found: 1146 Table 'vantage.users' doesn't exist

这显然是因为 Artisan 尚未创建表,但所有文档似乎都说有一种方法可以使用 Fluent Query 来填充数据作为迁移的一部分。

有人知道怎么做吗?谢谢!

【问题讨论】:

    标签: php laravel migration mysql-error-1146


    【解决方案1】:

    如果您使用 Laravel 8 并希望使用 多个 记录进行初始化,您可以通过这两种方式中的任何一种来进行。

    1.不推荐的方式

    public function up()
        {
            Schema::create('categories', function (Blueprint $table) {
                $table->id();
                $table->string('name');
                $table->timestamps();
            });
    
            DB::table('categories')->insert(
                array(
                    [
                        'name' => 'Category1',
                    ],
                    [
                        'name' => 'Category2',
                    ],
                    [
                        'name' => 'Category3',
                    ],
                )
            );
        }
    

    上述方法没问题,但会将 created_atupdated_at 列留空。

    2。推荐方式

     public function up()
        {
            Schema::create('categories', function (Blueprint $table) {
                $table->id();
                $table->string('name');
                $table->timestamps();
            });
    
    
            $data =  array(
                [
                    'name' => 'Category1',
                ],
                [
                    'name' => 'Category2',
                ],
                [
                    'name' => 'Category3',
                ],
            );
            foreach ($data as $datum){
                $category = new Category(); //The Category is the model for your migration
                $category->name =$datum['name'];
                $category->save();
            }
    
        }
    

    【讨论】:

      【解决方案2】:

      这里很好地解释了为什么使用 Laravel 的 Database Seeder 比使用 Migrations 更可取:https://web.archive.org/web/20171018135835/http://laravelbook.com/laravel-database-seeding/

      尽管按照官方文档中的说明进行操作会更好,因为上面链接中描述的实现似乎不起作用并且不完整。 http://laravel.com/docs/migrations#database-seeding

      【讨论】:

      • 我同意你的看法,艾琳。不要将迁移与种子数据混合在一起,因为您很可能希望在开发环境中而不是在生产环境中植入一些数据。
      • 好点,但在某些情况下,生产环境中必须存在某些数据。例如,第一个默认管理员用户必须存在,客户才能首次登录,一些预设的授权角色必须存在,一些业务逻辑数据也可能立即需要。因此,我认为应该将强制性数据添加到迁移中(这样您也可以通过单独的迁移来上/下数据记录),但可以留下种子用于开发。
      • 一个小笔记;数据库种子的链接现在是:laravel.com/docs/5.3/seeding
      • 请附上链接文章的相关部分。不鼓励Link only answers。你的第一个链接已经失效了,我不得不从archive.org取回它!
      【解决方案3】:

      如果您已经填写了列并添加了新列,或者您想用新的模拟值填写旧列,请执行以下操作:

      public function up()
      {
          DB::table('foydabars')->update(
              array(
                  'status' => '0'
              )
          );
      }
      

      【讨论】:

        【解决方案4】:

        我尝试了这种 DB 插入方法,但由于它不使用模型,因此它忽略了我在模型上具有的 sluggable 特征。因此,鉴于此表的模型存在,一旦它迁移,我认为该模型将可用于插入数据。我想出了这个:

        public function up() {
                Schema::create('parent_categories', function (Blueprint $table) {
                    $table->bigIncrements('id');
                    $table->string('name');
                    $table->string('slug');
                    $table->timestamps();
                });
                ParentCategory::create(
                    [
                        'id' => 1,
                        'name' => 'Occasions',
                    ],
                );
            }
        

        这工作正常,并且还考虑到了我的模型上的 sluggable 特性来自动为这个条目生成一个 slug,并且也使用了时间戳。 注意。添加 ID 不是必需的,但是,在此示例中,我希望为我的类别提供特定的 ID。 在 Laravel 5.8 上测试过

        【讨论】:

          【解决方案5】:

          另一种干净的方法是定义一个私有方法来创建实例并持久化相关模型。

          public function up()
          {
              Schema::create('roles', function (Blueprint $table) {
                  $table->increments('id');
                  $table->string('label', 256);
                  $table->timestamps();
                  $table->softDeletes();
              });
          
              $this->postCreate('admin', 'user');
          }
          
          private function postCreate(string ...$roles)  {
              foreach ($roles as $role) {
                  $model = new Role();
                  $model->setAttribute('label', $role);
                  $model->save();
              }
          }
          

          使用此解决方案,Eloquent 将生成时间戳字段。

          编辑: 最好使用播种系统来区分数据库结构生成和数据库人口。

          【讨论】:

          • 我喜欢这个...它完全符合我的需要,在迁移时默认添加一些用户角色。需要确保导入模型或直接引用它$model = new App\UserRoles();,但除此之外......完美!
          【解决方案6】:

          我知道这是一篇旧帖子,但由于它出现在谷歌搜索中,我想我会在这里分享一些知识。 @erin-geyer 指出,混合迁移和播种者可能会让人头疼,@justamartin 反驳说,有时您希望/需要在部署过程中填充数据。

          我会更进一步说,有时希望能够一致地推出数据更改,这样您就可以部署到登台,看到一切都很好,然后放心地部署到生产中相同的结果(并且不必记住运行一些手动步骤)。

          但是,将种子和迁移分开仍然是有价值的,因为它们是两个相关但截然不同的问题。我们的团队通过创建称为播种机的迁移来妥协。这看起来像:

          public function up()
          {
              Artisan::call( 'db:seed', [
                  '--class' => 'SomeSeeder',
                  '--force' => true ]
              );
          }
          

          这允许您像迁移一样执行一次种子。您还可以实现阻止或增强行为的逻辑。例如:

          public function up()
          {
              if ( SomeModel::count() < 10 )
              {
                  Artisan::call( 'db:seed', [
                      '--class' => 'SomeSeeder',
                      '--force' => true ]
                  );
              }
          }
          

          如果 SomeModel 少于 10 个,这显然会有条件地执行您的播种机。如果您想将播种器作为标准播种器包含在您调用 artisan db:seed 以及迁移时执行的标准播种器中,这将非常有用,这样您就不会“加倍”。您还可以创建一个反向播种器,以便回滚按预期工作,例如

          public function down()
          {
              Artisan::call( 'db:seed', [
                  '--class' => 'ReverseSomeSeeder',
                  '--force' => true ]
              );
          }
          

          需要第二个参数--force才能让seeder在生产环境中运行。

          【讨论】:

          • 这是迄今为止最好的答案。分离关注点的可维护代码!
          • 我会小心考虑从迁移脚本调用播种机的长期影响。迁移脚本是日期/时间版本的,而播种机通常不是。在开发过程中,seeder 的需求经常发生变化,导致版本化的迁移脚本运行非版本化的 seeder 的可能性——破坏了幂等性。换句话说,每天运行同一组迁移脚本可能会产生不同的结果。
          • 我已经有一段时间没有发布这个了,我想提供我们使用这种技术的经验。总的来说,它对我们来说效果很好,如果我不得不再做一次,我会的。也就是说,有一个问题需要注意。 @originalbryan 是完全正确的,结果是我们偶尔会在启动新数据库时遇到迁移中断的情况,因为随着迁移的运行,播种机(和模型)比数据库更新(因为我们可能播种在架构完全更新之前)。发生这种情况时,我们会更新旧迁移以解决该问题。
          • @darrylkuhn 我听说更新旧迁移文件不是一个好习惯 - 您应该创建新的迁移文件而不是更新旧文件 - 这是设计迁移文件的“工作流程”
          • Laravel 的所有语言都暗示播种器是用于测试数据的,所以我认为在设计时应该牢记这一点。区分属于应用的数据与测试数据非常重要,并且在迁移中直接包含所需的数据可以非常清楚地区分。
          【解决方案7】:

          这应该做你想做的。

          public function up()
          {
              DB::table('user')->insert(array('username'=>'dude', 'password'=>'z19pers!'));
          }
          

          【讨论】:

            【解决方案8】:

            不要将 DB::insert() 放在 Schema::create() 中,因为 create 方法必须先完成表的创建,然后才能插入内容。试试这个:

            public function up()
            {
                // Create the table
                Schema::create('users', function($table){
                    $table->increments('id');
                    $table->string('email', 255);
                    $table->string('password', 64);
                    $table->boolean('verified');
                    $table->string('token', 255);
                    $table->timestamps();
                });
            
                // Insert some stuff
                DB::table('users')->insert(
                    array(
                        'email' => 'name@domain.com',
                        'verified' => true
                    )
                );
            }
            

            【讨论】:

            • 以及如何插入多条数据?
            • @SuperMario'sYoshi 我认为是这样的DB::table('users')-&gt;insert([ ['email' =&gt; 'taylor@example.com', 'votes' =&gt; 0], ['email' =&gt; 'dayle@example.com', 'votes' =&gt; 0] ]);
            猜你喜欢
            • 1970-01-01
            • 2022-08-17
            • 2019-11-25
            • 2021-08-22
            • 2018-04-04
            • 2019-05-02
            • 1970-01-01
            • 2010-10-06
            • 1970-01-01
            相关资源
            最近更新 更多