在Laravel迁移文件中填充数据库


115

我正在学习Laravel,并且有一个有效的迁移文件创建了一个users表。我正在尝试在迁移过程中填充用户记录:

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来填充数据,作为迁移的一部分。

有人知道吗?谢谢!

Answers:


215

不要将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
        )
    );
}

5
以及如何插入多个数据?
Sahbaz

6
@ SuperMario'sYoshi我觉得是这样的DB::table('users')->insert([ ['email' => 'taylor@example.com', 'votes' => 0], ['email' => 'dayle@example.com', 'votes' => 0] ]);
Денис

80

我知道这是一篇旧文章,但是由于它出现在Google搜索中,所以我想在这里分享一些知识。@ 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 ]
        );
    }
}

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

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

--force需要第二个参数才能使播种机在生产环境中运行。


2
到目前为止,这是最好的答案。可维护的代码将关注点分开!
赫尔森特

18
我会仔细考虑从迁移脚本中调用种子服务器的长期影响。迁移脚本具有日期/时间版本,而种子服务器通常没有。在开发期间,种子服务器的需求经常发生变化,从而导致版本化迁移脚本运行非版本种子服务器的可能性–破坏了幂等性。换句话说,每天运行同一组迁移脚本可能会产生不同的结果。
originalbryan

2
自从我发布此消息已有一段时间以来,我想提供使用此技术的经验。总体而言,它对我们来说运作良好,如果我不得不再做一次,我会的。也就是说,有一个陷阱需要注意。@originalbryan完全正确,其结果是,我们在纺出新的数据库时偶尔会遇到迁移中断的情况,因为在迁移过程中,种子(和模型)运行的时间比数据库更新的时间(因为我们可以播种)在架构完全更新之前)。发生这种情况时,我们将更新旧的迁移以解决该问题。
darrylkuhn

@darrylkuhn我听说更新旧的迁移文件不是一个好习惯-而不是更新旧的文件,您应该创建新的迁移文件-这是设计迁移文件的“工作流程”
KamilKiełczewski17年

2
Laravel的所有语言都暗示着种子是用于测试数据的,因此我认为设计时应牢记这一点。区分作为应用程序一部分的数据与测试数据是很重要的,并且在迁移中直接包含必需的数据可以使这种区分非常清楚。
Brettins

12

这是一个很好的解释,说明了为什么使用Laravel的Database Seeder比使用Migrations更可取:http ://laravelbook.com/laravel-database-seeding/

虽然,按照官方文档中的说明进行操作是一个更好的主意,因为上述链接中描述的实现似乎无效且不完整。 http://laravel.com/docs/migrations#database-seeding


1
我同意你艾琳。不要将迁移与种子数据混合在一起,因为您很可能希望在开发环境中而不是生产环境中播种一些数据。
Daniel Vigueras 2014年

18
很好,但是在某些情况下,生产环境中必须存在一些数据。例如,必须存在第一个默认的admin用户,以便客户可以首次登录,必须存在一些预设的授权角色,还可能立即需要一些业务逻辑数据。因此,我认为应该将强制性数据添加到迁移中(以便您可以通过单独的迁移来上/下数据记录),但是种子可以留给开发。
JustAMartin 2015年

小笔记;现在,指向数据库种子的链接为:laravel.com/docs/5.3/seeding
magikMaker '16

3

这应该做您想要的。

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

1

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

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();,但除此之外...完美!
FAB

1

我尝试了这种DB插入方法,但是由于它不使用模型,因此它忽略了我在模型上具有的迟滞特性。因此,考虑到该表的模型存在,一旦迁移,我就认为该模型可用于插入数据。我想到了这个:

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',
            ],
        );
    }

这可以正常工作,并且还考虑了我的模型上的可拖滞特征,以便为此条目自动生成一个段,并也使用时间戳。注意 无需添加ID,但是在此示例中,我想为我的类别指定特定的ID。经过测试可在Laravel 5.8上工作


0

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

public function up()
{
    DB::table('foydabars')->update(
        array(
            'status' => '0'
        )
    );
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.