当前模型与旧迁移不兼容
Current model is incompatible with old migrations
我有以下情况(我将其描述为历史记录):
- 我使用迁移文件 A[=45= 设置项目
User
模型(和 users
table) ]
一段时间后,我添加了 user_modules table 多对多,我被迫在迁移文件 B 的 schama 更新期间初始化这个数组。我通过
User::chunk(100, function($users) {
foreach ($users as $user) {
$user->userModule()->create();
}
});
- 一段时间后,我需要通过在迁移文件 C[=44= 中添加软删除(第 delete_at 列)来更新
User
模型和 table ] 和 User
模型中的字段 $dates=['deleted_at']
。
- 然后我开发系统并添加更多迁移,但在某个时候新的开发人员加入我们的团队,他必须从头开始构建数据库模式,所以他 运行
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.
我有以下情况(我将其描述为历史记录):
- 我使用迁移文件 A[=45= 设置项目
User
模型(和users
table) ] 一段时间后,我添加了 user_modules table 多对多,我被迫在迁移文件 B 的 schama 更新期间初始化这个数组。我通过
User::chunk(100, function($users) { foreach ($users as $user) { $user->userModule()->create(); } });
- 一段时间后,我需要通过在迁移文件 C[=44= 中添加软删除(第 delete_at 列)来更新
User
模型和 table ] 和User
模型中的字段$dates=['deleted_at']
。 - 然后我开发系统并添加更多迁移,但在某个时候新的开发人员加入我们的团队,他必须从头开始构建数据库模式,所以他 运行
php artisan:migrate
但他在迁移文件中遇到错误B:
[Illuminate\Database\QueryException (42S22)]
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'users.deleted_at' in 'where clause' (SQL: select * fromusers
whereusers
.deleted_at
is null order byusers
.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.