laravel - 使用数据库管理器迁移脚本更新 laravel/eloquent 模型时删除 sqlite 列失败
问题描述
我在尝试在我的 Laravel 应用程序中运行测试时遇到问题。我有一个表结构如下:
这些 SQL 查询是由使用 TablePlus 的导出脚本生成的,因为我认为这是共享表结构的最简单方法。
迁移后(现在)
CREATE TABLE `business_system_role_location_type` (
`business_system_role_id` char(36) COLLATE utf8mb4_unicode_ci NOT NULL,
`location_type_id` char(36) COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`business_system_role_id`,`location_type_id`),
KEY `business_system_role_loc_type_fk` (`location_type_id`),
CONSTRAINT `business_system_role_loc_type_fk` FOREIGN KEY (`location_type_id`) REFERENCES `location_types` (`id`),
CONSTRAINT `business_system_role_loc_type_role_id_fk` FOREIGN KEY (`business_system_role_id`) REFERENCES `business_system_roles` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
迁移前
CREATE TABLE `business_system_role_location_type` (
`business_system_role_id` char(36) COLLATE utf8mb4_unicode_ci NOT NULL,
`location_type` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`business_system_role_id`,`location_type`),
CONSTRAINT `business_system_role_loc_type_role_id_fk` FOREIGN KEY (`business_system_role_id`) REFERENCES `business_system_roles` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
如您所见,我已经运行了迁移并删除了该location_type
字段并将其替换为新location_types
表的外键。business_system_role_id
和都location_type
设置为 UNIQUE PRIMARY KEY。
这一切似乎都适用于 MySQL,但是一旦我尝试运行我的任何测试(使用 SQLite),它就会停止工作并抱怨:
Illuminate\Database\QueryException : SQLSTATE[23000]: Integrity constraint violation: 19 NOT NULL constraint failed: business_system_role_location_type.location_type (SQL: insert into "business_system_role_location_type" ("business_system_role_id", "location_type_id") values (bb2051c2-1b5c-498d-bbcf-6dd9e20c4803, 38215722-bcba-4cac-8c83-fe867d8d8e65))
问题
business_system_role_location_type.location_type
为什么当该列不再存在时我得到一个 NOT NULL 约束?我在迁移之前尝试过设置location_type
,nullable->(true)
假设它可能会更新一些 SQLite 设置,但这不起作用。
我尝试调整我的代码,使其在$model->location_type = 'something'
之前执行$model->save()
,并且有效......即使该列不存在。所有对它的引用都已被删除。我不想在这里使用解决方法,并且想深入了解此错误的原因。
模型如下所示:
class BusinessSystemRoleLocationType extends Model
{
protected $table = 'business_system_role_location_type';
protected $fillable = [
'business_system_role_id',
'location_type_id',
];
public $incrementing = false;
public $timestamps = false;
public function businessSystemRole(): BelongsTo
{
return $this->belongsTo(
BusinessSystemRole::class,
'business_system_role_id',
'id'
);
}
}
在这里的任何帮助将不胜感激。:)
编辑 - 迁移
这是处理此表的迁移部分:
// Add location_type_id field to table
Schema::table('business_system_role_location_type', function (Blueprint $table) {
// Must be nullable until it is populated with data
$table->uuid('location_type_id')
->nullable()
->after('business_system_role_id');
});
// Assign location_type_id value to all entries
BusinessSystemRoleLocationType::all()->each(function ($businessSystemRoleLocationType) {
$locationTypeDataSetIndex = \array_search(
$businessSystemRoleLocationType->location_type,
\array_column($this->locationTypeDataSet, 'existsAs'),
true
);
if ($locationTypeDataSetIndex !== false) {
$newLocationTypeData = $this->locationTypeDataSet[$locationTypeDataSetIndex];
$newLocationType = LocationType::whereSlug($newLocationTypeData['slug'])->get()->first();
} else {
$newLocationType = LocationType::all()->first();
}
$businessSystemRoleLocationType->location_type_id = $newLocationType->id;
$businessSystemRoleLocationType->save();
});
// Adjust primary index and add foreign keys, and drop location_type field from table
Schema::table('business_system_role_location_type', function (Blueprint $table) {
$table->dropForeign('business_system_role_loc_type_role_id_fk');
$table->dropPrimary(['business_system_role_id', 'location_type']);
});
Schema::table('business_system_role_location_type', function (Blueprint $table) {
// ATTEMPT TO SET FIELD TO NULLABLE BEFORE REMOVING IT, MAYBE THIS WILL FIX THE NOT NULL CONSTRAINT ERROR?
$table->string('location_type')->nullable()->change();
});
Schema::table('business_system_role_location_type', function (Blueprint $table) {
$table->foreign('location_type_id', 'business_system_role_loc_type_fk')
->references('id')
->on('location_types');
$table->foreign('business_system_role_id', 'business_system_role_loc_type_role_id_fk')
->references('id')
->on('business_system_roles')
->onDelete('cascade');
// Now set not nullable UUID (Doctrine (change()) does not support UUID type)
$table->string('location_type_id', 36)->change();
$table->primary(['business_system_role_id', 'location_type_id'], 'business_system_role_loc_type_pk');
$table->dropColumn('location_type');
});
编辑 2 - 解决方案
我在这里编辑以提供我的解决方案 - 尽管我将保持开放状态,因为其他人很可能会提供更好的答案。
据我所知,为了删除 SQLite 数据库中的约束,建议删除表并重新创建它。(见这里:https ://stackoverflow.com/a/4007086/9675332 )。似乎 SQLite 将这些约束保存在某处,并且实际上并没有仅仅因为您删除了列而将它们删除。我真的不想走这条路,所以这就是我所做的:
解决方案 1:我修改了我的迁移以在删除它之前将字段设置为具有默认值,并且这确实通过了测试(尽管它随后在 UNIQUE 约束上失败,所以在我的情况下它不是一个可行的解决方案,但可能很好用为他人!)
解决方案 2:实际上可能我应该做的事情。我只是将列重命名为location_type
tolocation_type_id
并手动将其设置为char(36)
. 这似乎已经更新了后台的所有内容,现在它通过了测试。
解决方案
推荐阅读
- python - Pandas:返回每组出现频率最高的值(可能没有应用)
- ssh - Windows 上的 ssh 连接被拒绝(wsl)
- python-3.x - 将列表转换为 PCollection
- c++ - 为什么我的 if 语句在它应该评估的时候没有评估 false?
- arrays - 如何使用 Powershell 为文件中的每一行创建一个新数组?
- azure - 尝试在 Azure 上部署无框架静态 Web 应用程序时,为什么我会从 GitHub Actions 收到构建错误?
- sql-server - 考虑到重叠,有没有更快的方法来增加时间范围?
- ios - 发布内容后的最佳转场
- c# - 为什么使用 string.Join 时空值会自动转换为空字符串?
- django - 如何查看一周内的注册总数?