如何强制核心数据重建sqlite数据库模型?

时间:2010-03-01 15:50:00

标签: iphone core-data sqlite

在我的应用程序中,我有时需要重建并重新填充数据库文件。 SQLite数据库由CoreData堆栈创建和管理。

我要做的是删除文件,然后简单地重新创建persistentStoreCoordinator对象。

它可以在模拟器下运行但不在设备上运行,我遇到了这样的错误:

NSFilePath = "/var/mobile/Applications/936C6CC7-423A-46F4-ADC0-7184EAB0CADD/Documents/MYDB.sqlite";
NSUnderlyingException = I/O error for database at /var/mobile/Applications/936C6CC7-423A-46F4-ADC0-7184EAB0CADD/Documents/MYDB.sqlite.  SQLite error code:1, 'table ZXXXX already exists';

我无论如何也无法找到原因。它表示两个不同的问题 - Cocoa错误256表示文件不存在或不可读。但是在创建persistenStoreCoordinator之后创建了文件 IS ,尽管它是空的,但在执行一些查询后它会消失。

表示尝试创建alredy现有表的第二条消息在这种情况下非常奇怪。

我很困惑,无法明白这里发生了什么。我的代码如下所示:

NSString *path = [[WLLocalService dataStorePath] relativePath];
NSError *error = nil;

WLLOG(@"About to remove file %@", path);

[[NSFileManager defaultManager] removeItemAtPath: path error: &error];

if (error != nil) {
 WLLOG(@"Error removing the DB: %@", error);
}


[self persistentStoreCoordinator];

WLLOG(@"Rebuild DB result %d", [[NSFileManager defaultManager] fileExistsAtPath: path]);

在此代码被执行后,DB文件存在但是为空。当执行第一次查询(以及所有后续查询)时,它会给我上面的错误并且文件消失。

有人知道它有什么问题吗?

非常感谢你指出了正确的方法!

3 个答案:

答案 0 :(得分:18)

Core Data堆栈不喜欢你删除它下面的文件。如果您要删除文件,则应拆除堆栈,删除文件,然后重新构建堆栈。这将消除这个问题。

部分问题是堆栈会保留文件中数据的缓存。当您删除文件时,您无法清除该缓存,然后您将Core Data置于未知且不稳定的状态。

您可以尝试通过调用NSPersistentStoreCoordinator告诉-removePersistentStore:error:删除文件,然后通过调用-addPersistentStoreWithType:configuration:URL:options:error:添加新商店。我目前在ZSync中正在做这件事,它运作得很好。

答案 1 :(得分:8)

我在我的app委托中使用以下方法-resetApplicationModel,它对我来说很好。

您可能不需要kApplicationIsFirstTimeRunKey用户默认值,但我使用它来测试是否使用名为-setupModelDefaults的自定义方法使用默认设置填充Core Data存储,我也从{{{ 1}}如果首次运行标志为-applicationDidFinishLaunching:

YES

答案 2 :(得分:1)

您可以将sqlite数据库的“干净”副本作为应用程序包的一部分保留,然后只要您想要刷新数据库,就可以复制文档目录中的版本。

以下是来自应用程序的一些代码(虽然此版本不会复制和现有数据库):

// Check for the existence of the seed database
// Get the path to the documents directory and append the databaseName
NSString* databasePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent: kDatabaseName];

NSFileManager* fileManager = [NSFileManager defaultManager];
if ( ![fileManager fileExistsAtPath: databasePath] ) 
{
    NSString* databasePathFromApp = [[[NSBundle mainBundle] resourcePath] 
                                     stringByAppendingPathComponent: kDatabaseName];

    [fileManager copyItemAtPath: databasePathFromApp 
                         toPath: databasePath 
                          error: nil];
}
[fileManager release];