【问题标题】:What's the best way to refactor a database and its data? (Laravel 5.2)重构数据库及其数据的最佳方法是什么? (Laravel 5.2)
【发布时间】:2017-06-08 00:39:22
【问题描述】:

我试图弄清楚如何在 Laravel 5.2 的迁移中处理结构和数据相关的变化。 目前,我只是在对数据库进行结构更改后更改现有数据。 但这似乎与版本控制代码冲突。

一个简单的例子

owner_id 列应添加到 teams 表中。简单迁移,没问题。之后,所有现有团队都应该获得这样的 id。因此,我也将其放入迁移中:

foreach ($teams as $team) {
    // get the first user of this team over a many-to-many-relationship-table `team_user`
    $team->owner_id = $team->users->first()->id;
    ...
}

乍一看还不错。

几天后提交,我决定在提到的关系表中添加一个透视列role。我添加了迁移,并在团队模型中添加了这样的内容:

public function users() {
    return $this->belongsToMany(...)->withPivot('role');
}

由此产生的问题

如果我现在想完全刷新本地数据库,第一次迁移时会出错。那是因为它调用了 $team->users,但在数据库的这种状态下,role 尚不可用,因此方法调用失败。这就像版本控制和数据库迁移之间的转换。

有没有干净的解决方案?

提前非常感谢, 理查德

【问题讨论】:

    标签: php laravel version-control migration


    【解决方案1】:

    通常迁移是 DDL(数据定义语言),种子是 DML(数据操作语言)。

    迁移数据库表是一个顺序问题。您不能添加依赖于某些 DDL 的代码,这些代码可能在这些 DDL 运行之前执行。

    您必须考虑的另一件事是:迁移不是进行数据播种、修改、操作的地方,因为播种可能需要在开始播种之前完成所有数据定义。这就是 Laravel 有数据播种的原因。

    因此,播种、修复或更改数据之间没有区别,都是 DML。你可以在你的迁移中这样做,这不是被禁止的,但在那些你必须非常小心地撤消(向下)你在up 方法中采取的每一步。但有时很难操作回您的数据

    您的问题是您正试图通过关系访问一些数据,这些数据尚未准备好(或完成或播种),因为尚未运行的迁移尚未运行。所以你在DDL和DML之间有冲突,如果你分开处理它们就不会发生。

    通常数据播种仅用于测试,但如果您真的需要它,您可以在播种器中执行以下操作:

    <?php
    
    use Illuminate\Database\Seeder;
    
    class DatabaseSeeder extends Seeder
    {
        /**
         * Run the database seeds.
         *
         * @return void
         */
        public function run()
        {
            if (app()->environment('testing')) {
                $this->call(TestingSeeders::class);
            }
    
            $this->call(ProductionReadySeeders::class);
        }
    }
    

    或者您可以创建一个命令来播种您的数据:

    Artisan::command('app:seed', function ($email)
    {
        // Do whatever you need to seed your database tables
    });
    

    然后运行

    php artisan app:seed
    

    如果您想确保在您的应用程序中获得新版本的每个人也获得正确的数据,您可以使用 Composer 后执行命令来做到这一点:

    "post-install-cmd": [
       "Illuminate\\Foundation\\ComposerScripts::postInstall",
       "php artisan optimize",
       "php artisan migrate --force",
       "php artisan app:seed" 
    ],
    
    "post-update-cmd": [
       "Illuminate\\Foundation\\ComposerScripts::postUpdate",
         "php artisan optimize",
         "php artisan migrate --force", 
         "php artisan app:seed"
    ]
    

    【讨论】:

    • 谢谢!播种不是问题,在我当地的环境中,所有种子都是在迁移后应用的,并且效果很好。但是在生产中,我需要更改现有数据以匹配新的数据库结构。我该怎么办?
    • 播种、修复、修改数据没有区别,都是DML。你可以在你的迁移中这样做,这不是被禁止的,但在那些你必须非常小心地撤消(向下)你在up 方法中采取的每一步。但有时很难操作回您的数据。您的问题是您试图通过关系访问一些数据,这些数据尚未准备好(或完成或播种),因为尚未运行的迁移尚未运行。所以你在DDL和DML之间有冲突,如果你分开处理它们就不会发生。
    • 好的,那么将所有“更改现有数据”逻辑放入单独的工匠命令中可能是一种解决方案?然后可以在生产中部署,运行迁移,然后运行命令。但是,每个想要签出新功能的人也需要在迁移后运行此命令。而且当不只有一个迁移时,他必须确保他运行多个这样的命令,不是吗?感谢您的帮助:)
    • 是的,这可能是个问题,但您有办法确保每个人都能以应有的方式获得正确的数据。编辑显示一种方式,还有很多其他方式。
    • 好的,再次感谢,我会看看我能做到什么。您如何看待仅使用干净的数据库查询来更改现有数据的可能性?这会将其与应用程序代码分开,但确保每次迁移后数据库都处于每个开发人员的计划状态。这将使 DML 和 DDL 更紧密地结合在一起,但为了简单起见,这可能是可以的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-20
    相关资源
    最近更新 更多