咨询:如何用GRDB修改Case_Supplies_Media表的外键引用
修改GRDB中外键引用的正确实现
你的代码存在关键错误:你用UPDATE语句修改列数据,但外键是表结构的约束,并非列存储的值。要修改外键引用,必须调整表结构,而非更新数据。以下是适配GRDB的完整解决方案:
方案1:适配SQLite 3.35.0+(iOS 15+)
SQLite 3.35.0及以上版本支持直接删除外键约束,步骤更简洁:
func updateForeignKey() { let currentVersion = ModelData.get_Current_Version() guard currentVersion == 6 else { return } do { try Database_GRDB.shared.databaseConnection!.write { db in // 1. 删除原外键约束(SQLite默认约束名格式:<表名>_<列名>_fkey) try db.execute(sql: """ ALTER TABLE Case_Supplies_Media DROP CONSTRAINT Case_Supplies_Media_SupplyID_XRef_fkey; """) // 2. 添加新外键约束,指向Supplies_DVD_List的主键(替换为实际主键列名) try db.execute(sql: """ ALTER TABLE Case_Supplies_Media ADD CONSTRAINT fk_CaseSuppliesMedia_SupplyIDXRef_SuppliesDVDList FOREIGN KEY(SupplyID_XRef) REFERENCES Supplies_DVD_List(SupplyID); """) // 3. 更新版本号 try db.execute(sql: """ UPDATE My_Settings SET Version = :version WHERE SettingsID = :id; """, arguments: ["version": 7, "id": 1]) } } catch { print("更新外键约束失败!(AppDelegate) \(error)") } }
方案2:兼容旧版SQLite(iOS 14及以下)
旧版SQLite不支持直接删除约束,需通过重建表实现:
func updateForeignKey() { let currentVersion = ModelData.get_Current_Version() guard currentVersion == 6 else { return } do { try Database_GRDB.shared.databaseConnection!.write { db in // 1. 创建新表,复制原表结构并修改外键指向 try db.execute(sql: """ CREATE TABLE Case_Supplies_Media_New ( -- 复制原表所有列定义(示例包含CaseID,替换为你的实际列) CaseID INTEGER NOT NULL, SupplyID_XRef INTEGER NOT NULL, -- 其他列... PRIMARY KEY(CaseID), FOREIGN KEY(SupplyID_XRef) REFERENCES Supplies_DVD_List(SupplyID) ); """) // 2. 迁移原表数据到新表 try db.execute(sql: """ INSERT INTO Case_Supplies_Media_New SELECT * FROM Case_Supplies_Media; """) // 3. 删除原表并重命名新表 try db.execute(sql: "DROP TABLE Case_Supplies_Media;") try db.execute(sql: "ALTER TABLE Case_Supplies_Media_New RENAME TO Case_Supplies_Media;") // 4. 更新版本号 try db.execute(sql: """ UPDATE My_Settings SET Version = :version WHERE SettingsID = :id; """, arguments: ["version": 7, "id": 1]) } } catch { print("更新外键约束失败!(AppDelegate) \(error)") } }
关键注意事项
- 确认原约束名:不确定默认约束名时,可执行
PRAGMA foreign_key_list(Case_Supplies_Media);查询外键信息。 - 匹配主键类型:
Supplies_DVD_List的主键列类型必须和SupplyID_XRef完全一致。 - 事务安全:GRDB的
write闭包自动处理事务,任何步骤失败都会回滚所有操作,保证数据一致性。
内容的提问来源于stack exchange,提问作者user11004336
相关产品推荐
相关产品推荐

