当前模型与旧迁移不兼容

Current model is incompatible with old migrations

我有以下情况(我将其描述为历史记录):

  1. 我使用迁移文件 A[=45= 设置项目 User 模型(和 users table) ]
  2. 一段时间后,我添加了 user_modules table 多对多,我被迫在迁移文件 B 的 schama 更新期间初始化这个数组。我通过

    User::chunk(100, function($users) {
        foreach ($users as $user) {
            $user->userModule()->create();
        }
    });
    
  3. 一段时间后,我需要通过在迁移文件 C[=44= 中添加软删除(第 delete_at 列)来更新 User 模型和 table ] 和 User 模型中的字段 $dates=['deleted_at']
  4. 然后我开发系统并添加更多迁移,但在某个时候新的开发人员加入我们的团队,他必须从头开始构建数据库模式,所以他 运行 php artisan:migrate 但他在迁移文件中遇到错误B:

[Illuminate\Database\QueryException (42S22)]
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'users.deleted_at' in 'where clause' (SQL: select * from users where users.deleted_at is null order by users.id asc limit 100 off set 0)

所以当前User模型不兼容迁移文件B

遇到这种情况怎么办?

我在哪里犯了错误以及如何防止将来出现这种情况?

这是因为软删除。当您将特征 SoftDeletes 添加到模型时,它会自动将 where users.deleted_at is null 添加到所有查询。解决此问题的最佳方法是将 withTrashed() 添加到迁移 B.

中的查询中

为此,请将迁移 B 中的查询更改为如下所示。这应该删除它试图访问不存在的 deleted_at 列的部分。毕竟,此迁移并不知道您稍后要添加软删除,因此访问所有用户,包括那些被删除的用户,是非常有意义的。

User::withTrashed()->chunk(100, function($users) {
    foreach ($users as $user) {
        $user->userModule()->create();
    }
});

您始终可以在 运行 迁移之前注释掉用户模型上的 SoftDelete 特性,但这是一个临时修复,因为您需要向所有未来的开发人员解释它。此外,有时 运行 php artisan migrate:fresh 会非常方便。您不想每次都记住注释掉该特征,因此添加 withTrashed() 似乎是我最理想的解决方案。

最后一点,我强烈建议不要向您的迁移添加种子。迁移应该 ONLY 用于架构更改。在这种情况下,我会使用控制台命令或控制台命令的组合。

例如,您可以创建一个由 php artisan check:user-modules 触发的控制台命令。在此命令中,您可以使用以下命令,仅当用户模块尚不存在时才会创建一个用户模块。

User::chunk(100, function($users) {
    foreach ($users as $user) {
        if (!$user->userModule()->exists()) {
            $user->userModule()->create();
        }
    }
});

您应该可以随时 运行 此命令,因为它不会覆盖现有的用户模块。

替代答案:在这种情况下,当我们需要在数据库架构更改后生成或转换一些数据时 - 我们 不应使用模型 (将来可以独立更改),而是使用 inserts/updates:

DB::table('users')->chunkById(100, function ($users) {
    foreach ($users as $user) {
        DB::table('user_modules')->insert(
            ['user_id' => $user->id, 'module_id' => 1]
        );
    }
});

正如 laravel documentation 中所写,播种器是为测试数据播种而设计的,而不是为数据转换而设计的——所以迁移文件可能是放置转换代码的好地方(它可以生成或更改一些生产模式更新后数据库中的数据)

Laravel includes a simple method of seeding your database with test data using seed classes.