4

刚刚偶然发现在 sqlite 中默认禁用外键这一事实。我有“删除级联”外键,删除父表记录不会删除子记录。各种帖子表明您需要在每个连接“PRAGMA foreign_keys = ON;”上启用它。那么,在 FMDatabase 的哪里启用它呢?我宁愿设置一些设置,而不是在每个 SQL stmt 之前运行命令。PS。我正在使用 FMDatabaseQueue。

4

4 回答 4

8

我快速检查并PRAGMA foreign_keys = ON;在 5.1 模拟器和 5.1 iPod Touch 上运行良好。正如 ccgus 建议的那样,您应该缓存数据库连接。如果您使用队列,只需缓存队列并重新组织您的代码,这样就不会在您每次需要使用数据库时创建新队列。使用您当前的方法,如果您不真正使用它但每次都创建新的队列,那么有什么意义呢?

但回到问题,正如您已经知道的那样,外键默认情况下是关闭的,因此您需要首先启用它。我设法做到了PRAGMA foreign_keys = ON;,这是我使用的更多测试代码:

//create database
NSString* dbPath = [(NSArray*)NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
dbPath = [dbPath stringByAppendingPathComponent:@"test.db"];
db = [FMDatabase databaseWithPath:dbPath];
if ([db open]) {
    NSLog(@"Database %@ opened", dbPath);
    //check for foreign_key
    NSString* sql = @"PRAGMA foreign_keys";
    FMResultSet *rs = [db executeQuery:sql];
    int enabled;
    if ([rs next]) {
        enabled = [rs intForColumnIndex:0];
    }
    [rs close];
    if (!enabled) {
        // enable foreign_key
        sql = @"PRAGMA foreign_keys = ON;";
        [db executeUpdate:sql];
        // check if successful
        sql = @"PRAGMA foreign_keys";
        FMResultSet *rs = [db executeQuery:sql];
        if ([rs next]) {
            enabled = [rs intForColumnIndex:0];
        }
        [rs close];
    }
    // do your stuff here, or just cache the connection
} else {
    NSLog(@"Failed to open %@", dbPath);
}

看起来相当简单,唯一想到的是您使用executeQuery而不是executeUpdate.

于 2012-05-08T11:11:54.560 回答
1

为什么必须在每个语句之前运行它?只需打开数据库,运行您的编译指示,然后缓存连接以供以后使用(无论如何您都应该这样做……)。

于 2012-05-07T23:55:31.913 回答
1

在 Swift 3 中,我使用此函数打开启用了外键的数据库。

func openDB()-> FMDatabase? {
    let fileURL = try! FileManager.default
        .url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
        .appendingPathComponent("name.sqlite")

    let database = FMDatabase(url: fileURL)

    guard database.open() else {
        print("Unable to open database")
        return nil
    }
    do {
        try database.executeQuery("PRAGMA foreign_keys = ON", values: nil)
    } catch {
        print("failed: \(error.localizedDescription)")
    }
    return database
}
于 2017-10-11T13:54:43.447 回答
0

尽管最初的问题是针对 Objective-C 的,但这里有一个对我很有效的 Swift 扩展,以防万一有人觉得它有用:


extension FMDatabase {
    var foreignKeys: Bool {
        get {
            guard let result = executeQuery("PRAGMA foreign_keys", withArgumentsIn: [])
            else { return false }
            
            defer { result.close() }
            
            guard result.next() else { return false }
            
            return result.bool(forColumnIndex: 0)
        }
        set {
            executeStatements("PRAGMA foreign_keys = \(newValue ? "ON" : "OFF");")
        }
    }
}

所以你可以db.foreignKeys = true在打开数据库后调用,你就完成了。

于 2021-10-22T22:18:54.440 回答