【发布时间】:2021-08-11 01:48:18
【问题描述】:
我已经尝试解决这个问题一段时间了。我正在通过 SQlite3 使用 Swift/SwiftUI 和 FMDB 编写应用程序。当在存在现有外键的表上执行删除时,我预计删除会失败。它没有,也没有抛出错误。
在 XCode 中,我与 libsqlite3.tbd 链接,日期为 2021 年 3 月 16 日修改。在 tbd 文件中,我发现: 安装名称:'/usr/lib/libsqlite3.dylib' 当前版本:321.3 兼容性版本:9
我在以下位置找到 libsqlite3.dylib: /System/Volumes/Data/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib 信息显示它创建于 2021 年 4 月 9 日。没有明显的版本
发生的情况是我在一个名为 BudgetedExpense 的表上有一个外键,指向一个名为 BudgetDescription 的表。
BudgetDescription DDL
CREATE TABLE budget_description (
id INTEGER DEFAULT (0)
PRIMARY KEY AUTOINCREMENT
UNIQUE,
income_expense_code INTEGER (8) NOT NULL
DEFAULT (0),
description STRING NOT NULL
DEFAULT (0),
income_or_expense INTEGER NOT NULL
DEFAULT (0)
);
BudgetedExpense DDL
CREATE TABLE budgeted_expense (
expense_id INTEGER NOT NULL
DEFAULT (0)
PRIMARY KEY AUTOINCREMENT
UNIQUE,
account_code INTEGER (8) NOT NULL
DEFAULT (0),
expense_code INTEGER (8) NOT NULL
DEFAULT (0),
budget_year INTEGER (4) NOT NULL
DEFAULT (0),
budget_month INTEGER (2) NOT NULL
DEFAULT (0),
expense_budget DECIMAL (12, 2) NOT NULL
DEFAULT (0),
expense_spent DECIMAL (12, 2) NOT NULL
DEFAULT (0),
unexpected_expense DECIMAL (12, 2) NOT NULL
DEFAULT (0),
category_code INTEGER (8) NOT NULL
DEFAULT (0),
hidden BOOLEAN NOT NULL
DEFAULT (0),
hidden_id INTEGER DEFAULT (0),
FOREIGN KEY (
account_code,
budget_year,
budget_month
)
REFERENCES budget (account_code,
budget_year,
budget_month),
FOREIGN KEY (
expense_code
)
REFERENCES budget_description (income_expense_code) ON DELETE RESTRICT,
FOREIGN KEY (
category_code
)
REFERENCES categories (category_code)
);
我执行数据库更新的 FMDB 代码是:
func updateDatabaseTable(query: String)-> Bool
{
var updateSuccessful: Bool = false
let pragmaQuery = "PRAGMA foreign_keys=ON;"
if openDatabase() {
do {
try database.executeUpdate(pragmaQuery, values: nil)
} catch {
}
queue.inTransaction() {
database, rollback in
do {
try database.executeUpdate(query, values: nil)
updateSuccessful = true
if showQuerys && updateSuccessful {
print("Update query is:\n \(query)")
}
}
catch {
rollback.initialize(to: true)
print(error.localizedDescription)
print(database.lastError())
print(database.lastErrorMessage())
print("UPDATE QUERY FAILED")
print(query)
updateSuccessful = false
}
}
_ = closeDatabase()
}
return updateSuccessful
}
删除 BudgetDescription 表中一行的 SQL 是:
// Delete a specific record for a given income/expense code.
func deleteBudgetDescriptionRecordSQL(forIncomeExpenseCode incomeExpenseCode: Int) -> String
{
let query =
"""
DELETE FROM \(budget_description_table)
WHERE \(income_expense_code_field) = \(incomeExpenseCode)
"""
return query
}
我写的函数是:
// **** DELETE BUDGET DESCRIPTION RECORD FOR A GIVEN ACCOUNT CODE **** //
func deleteBudgetDescriptionRecord(forIncomeExpenseCode incomeExpenseCode: Int) -> Bool
{
var updateResult: Bool
updateResult = updateBudgetDescriptions(updateQuery: deleteBudgetDescriptionRecordSQL(forIncomeExpenseCode: incomeExpenseCode))
if showQuerys {
print("\nQUERY: deleteBudgetDescriptionRecordSQL(forIncomeExpenseCode: incomeExpenseCode)")
print(deleteBudgetDescriptionRecordSQL(forIncomeExpenseCode: incomeExpenseCode))
}
if updateResult == false {
print("deleteBudgetDescriptionRecordSQL returned FALSE when executing QUERY:")
print(deleteBudgetDescriptionRecordSQL(forIncomeExpenseCode: incomeExpenseCode))
return updateResult
}
return updateResult
}
执行:
// ********************** PRIVATE DRIVER FUNCTIONS TO EXECUTE DBMANAGER UPDATE DATABASE TABLE METHOD ***********//
private func updateBudgetDescriptions(updateQuery: String) -> Bool
{
var updateResult: Bool
updateResult = DBManager.shared.updateDatabaseTable(query: updateQuery)
return updateResult
}
当我在名为 SQLiteStudio 的实用程序中执行此 DELETE sql 时,它会失败并显示 foreign_key 通知。但是当使用 FMDB 在同一个数据库上执行时,它会在没有错误或任何日志记录的情况下执行。
如果在删除时存在外键,我会在一定程度上依赖数据库完整性来引发错误。我已经为此工作了几天。
我有一个 XCode 项目可以演示这一点,但不知道在哪里或如何上传它以供他人检查。
如果有任何想法可以帮助我使约束发挥作用,我将不胜感激。
鲍勃
【问题讨论】:
-
也许this question 可以提供帮助
-
感谢您提供的建议链接。但是实施 PRAGMA foreign_key=on; 的解决方案已经在我的代码中了。
-
不确定这是否相关,但外键链接到普通列而不是其他表的主键有点奇怪,但也许这是有原因的。跨度>
-
嗯,这是一个想法,我会考虑的。 SQLiteStudio 中仍然遵守约束。只是不在带有 FMDB 的应用程序中