偶然发现,在sqlite中默认禁用外键。我有“on delete casdade”外键并删除父表记录不删除子记录。各种帖子表明您需要在每个连接上启用它“PRAGMA foreign_keys = ON;”。那么,在FMDatabase中启用它的位置?我宁愿设置一些设置,而不是在每个SQL stmt之前运行命令。 PS。我正在使用FMDatabaseQueue。
答案 0 :(得分: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
。
答案 1 :(得分:1)
为什么你必须在每个声明之前运行它?只需打开数据库,运行pragma,然后缓存连接以供以后使用(无论如何都应该这样做......)。
答案 2 :(得分:0)
在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
}