【问题标题】:iOS core data object model change in production applicationiOS 核心数据对象模型在生产应用中的变化
【发布时间】:2012-11-17 18:13:51
【问题描述】:

我目前有一个正在生产使用的应用。我对该应用的核心数据模型的下一版本进行了重大更改。

为了避免从旧数据模型到新数据模型的大量转换工作,我只是简单地重命名了新的对象模型和数据库,从而导致新版本的应用程序不再引用旧数据库(这不是一个问题,因为旧的数据库数据很小,不需要)。

但是,我确实需要旧数据库中的一条数据,我不希望用户需要手动将其重新输入到新数据库中。

我的问题: 将这条数据放入新数据库有哪些选择?

我可以对 sqlite 数据库运行查询并简单地进入新数据库吗?还是我需要创建一个完整的其他持久存储和对象模型来提取数据?

还是我一起错过了什么?

【问题讨论】:

    标签: iphone ios database sqlite core-data


    【解决方案1】:

    您似乎只需在用户首次运行更新后的应用时将数据复制到新数据库。那时你可能会清除旧的,所以它会占用空间。不知道还需要什么更复杂的解决方案。似乎足够了。

    【讨论】:

    • 我想我想知道最好/最简单的方法来做到这一点。我宁愿没有 2 个对象模型等......只是为了这个一次性操作。
    【解决方案2】:

    我同意,我认为您应该使用核心数据连接到旧数据库并提取数据,然后将其移动到新数据库。完成后,您应该使用以下内容删除旧的数据库文件(注意我假设您将核心数据结果存储到 SQLite 中):

    - (NSURL *)urlForDocumentsDirectoryWithFile:(NSString *)fileName {
        NSURL *docPath = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
        return [docPath URLByAppendingPathComponent:fileName];
    }
    
    - (void)deleteFileFromDocumentsIfExists:(NSString *)fileName {
        NSFileManager *fileManager = [NSFileManager defaultManager];
        NSError *error;
        NSURL *filePath = [self urlForDocumentsDirectoryWithFile:fileName];
        NSLog(@"Deleting file: %@", filePath.absoluteString);
        if ([fileManager fileExistsAtPath:[filePath path]])
        {
            BOOL success = [fileManager removeItemAtURL:filePath error:&error];
            if (!success) NSLog(@"Error: %@", [error localizedDescription]);
        }
    }
    

    删除代码:

    [self deleteFileFromDocumentsIfExists:@"MyOldDatabaseName.sqlite"];
    

    如果您只使用一次旧的对象模型,我不会担心拥有 2 个对象模型......永远。我可以看到在您的应用程序中“使用一次”代码是一种浪费,但即使跳过核心数据并手动查询仍然需要您拥有它。

    另外,我有一个 DataAccessManager 单元,我将所有核心数据的荒谬初始化代码转储到其中,这样我就可以轻松访问多个上下文,如果您担心您是手动编写的,您可能想要将其移至可共享的单元。

    【讨论】:

      【解决方案3】:

      感谢以上两个建议。我最终使用以下方法来解决我的问题:

      步骤:

      • 尝试连接旧的 SQLite 数据库。
      • 如果连接成功,读取记录。
      • 在托管对象上下文中创建一个新托管对象。
      • 用 sql 结果中的值填充托管对象中的值。
      • 保留托管对象。
      • 删除旧数据库。
      NSString *dbFilePath = [[self applicationDocumentsDirectoryString] stringByAppendingPathComponent:@"RPS.sqlite"]; sqlite3 *数据库; if (sqlite3_open([dbFilePath UTF8String], &database)) { NSLog(@"sqlite3_open: 失败"); } 别的 { NSString *nsquery = [[NSString alloc] initWithFormat:@"SELECT * FROM ztable"]; const char *query = [nsquery UTF8String]; sqlite3_stmt *语句; int prepareCode = (sqlite3_prepare_v2(database, query, -1, &statement, NULL)); 如果(准备代码 == SQLITE_OK){ 我的表 *myTableRecord; NSLog(@"即将开始添加数据"); 而(sqlite3_step(语句)== SQLITE_ROW) { NSLog(@"**************** 行返回 ******************"); myObject = [NSEntityDescription insertNewObjectForEntityForName:@"myTable" inManagedObjectContext:self.managedObjectContext]; [myTable setValue:[NSString stringWithFormat:@"%s",(char *)sqlite3_column_text(statement, 7)] forKey:@"field1"]; [myTable setValue:[NSString stringWithFormat:@"%s",(char *)sqlite3_column_text(statement, 8)] forKey:@"field2"]; [自我保存上下文]; } sqlite3_finalize(语句); NSLog(@"添加了 sqlite3 数据"); } 别的 { NSLog(@"准备代码不正确:%d",prepareCode); } NSError *错误; NSFileManager *filemgr = [[NSFileManager alloc] init]; [filemgr removeItemAtPath:dbFilePath 错误:&err]; NSLog(@"删除了旧的 sqlite3 数据库"); }

      【讨论】:

      • 这是一个不错的解决方案。我假设您没有尝试就地 CoreData 迁移,因为您的模型更改非常严重?当然,对于“简单”的模型更改,自动迁移是要走的路……
      • 正是……自动迁移并没有涵盖我所做的所有关系更改等。这可能有点hacky..但很简单:)。
      • 简单的作品。 :-) 有一种方法可以编写不是自动迁移的“真实”迁移,并隐藏所有隐藏的东西(如 SQLite 数据库)。但这可能是正确的“真正”工作。 :-)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-08-15
      • 1970-01-01
      • 1970-01-01
      • 2012-06-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多