Core data 核心数据设计-如何同时拥有应用程序数据和用户数据?

Core data 核心数据设计-如何同时拥有应用程序数据和用户数据?,core-data,ios7,database-design,Core Data,Ios7,Database Design,我的应用程序附带了一组基本信息。用户可以添加或编辑此信息。但有时,我需要能够更新基础数据。我不想触碰用户更改/添加。我已经看过了,但是使用的类比有点陌生 这一定是一个常见的问题,我希望能听到这种混合数据集的实践和经验 当用户修改了一个对象时,我正在考虑为每个记录设置一个标志。然而,这带来了一个问题,即他们可能是意外地这样做的 我还可以创建两个数据集,但这会带来重复问题 所以想法是最受欢迎的。所以从我所能告诉你的,你有4个要求(实际上,可能是4个不同的问题) 应用程序数据和用户数据应分开保存 应用

我的应用程序附带了一组基本信息。用户可以添加或编辑此信息。但有时,我需要能够更新基础数据。我不想触碰用户更改/添加。我已经看过了,但是使用的类比有点陌生

这一定是一个常见的问题,我希望能听到这种混合数据集的实践和经验

当用户修改了一个对象时,我正在考虑为每个记录设置一个标志。然而,这带来了一个问题,即他们可能是意外地这样做的

我还可以创建两个数据集,但这会带来重复问题


所以想法是最受欢迎的。

所以从我所能告诉你的,你有4个要求(实际上,可能是4个不同的问题)

  • 应用程序数据和用户数据应分开保存
  • 应用程序附带一组“基本”数据
  • 应用程序“基础”数据将由用户编辑
  • 应用程序“基础”数据需要定期更新,但不能与用户更改冲突
  • 应用程序数据和用户数据应分开保存。 第一个要求,应用程序和用户数据的分离,涉及到。不正确遵守数据存储指导原则可能导致应用商店拒绝(2.23:应用程序必须遵守iOS数据存储指导原则,否则将被拒绝),并有一个神秘的响应指向您。数据存储指导原则适用于控制备份的大小、设备空间不足时自动清除文件的策略,以及关于发生什么情况的一般指导原则(开发人员的理解是错误的)

    用户创建或编辑的数据属于
    ,其他子目录属于该目录

    这对核心数据应用程序意味着什么? 用户数据和应用程序数据应在不同的位置使用不同的存储文件。您仍将使用一个NSPersistentStoreCoordinator,但向其中添加两个不同的持久存储。您的托管对象模型将需要两种不同的配置—每个存储都有自己的配置,每个实体都连接到其中一种配置

    配置:

    这将推动数据模型的设计-您不应该在两个不同的存储中存在单一实体类型,这意味着您将无法在用户存储中存在“用户编辑的Foo实体”,而在应用程序存储中存在“应用程序提供的Foo实体”-除非Foo是抽象的,每个商店都有自己的具体实体(这只是一个可能的解决方案)。 跨存储关系可以实现为获取的属性(稍后将详细介绍)

    由于核心数据SQLite持久存储不是单个文件,而是文件的集合,因此建议每个存储都有自己的存储文件目录-这使得保存、删除、备份、应用程序更新等更加高效和可靠。 考虑到这一点,您的文件结构应该如下所示:

    应用程序存储URL:
    以确保在将来的版本中修复此问题。获取的属性对于遵守数据存储指南至关重要

    应用程序附带一组“基本”数据 有多种方法可以处理此问题:

  • 从JSON/XML/property list/CSV/等数据创建托管对象,并插入托管对象上下文并保存
  • 除了用户和应用程序存储之外,还可以将存储作为只读存储
  • 除了用户存储和应用程序存储之外,还可以使用一组预构建的SQLite文件(例如来自命令行工具)作为只读存储
  • 从3中的预构建存储开始,但执行迁移以将这些对象移动到另一个存储中
  • 各有优缺点:

  • 这可能是缓慢、复杂、难以维护且容易出错的。这是一种更常见的方法,也是最糟糕的方法之一。认真地但如果这是你最容易维护的,那就给你更多的动力
  • 还记得我之前说过给定实体不应该存在于多个存储/配置中吗?我没有告诉你全部真相。给定实体应仅存在于单个可写存储中。对于我们的Foo实体,我们可以有一个可写存储,但可以有任意多个只读存储。如果使用选项
    nsreadonlypersistentstoreption
    将存储添加到持久存储协调器中,则该存储将是只读的。这意味着您可以使用预构建的NSSQLiteStore,该NSSQLiteStore是只读的,并且包含“初学者”数据,或者您也可以更雄心勃勃地使用可以读取其他数据格式的NSAtomicStore或NSIncrementalStore实现。这是最不容易出错的解决方案,也是最容易维护的解决方案之一
  • 要为此创建一组SQLite文件,您需要构建一个工具,将大部分核心数据代码和托管对象模型作为应用程序共享。否则这与3相同
  • 您可以在存储(如选项2或3中使用的存储)之间执行迁移,并使用迁移将数据移动到应用程序或用户存储中。迁移通常比执行类似选项1的操作性能更高,尽管它们有一些限制:例如,轻量级迁移可以很好地工作,但无法防止重复或冲突。需要进行自定义迁移。这样的迁移如下所示:
    sqlStore=[persistentstorecordinator migratePersistentStore:store-tour:[self-applicationStoreURL]选项:nil with-type:NSSQLiteStoreType-error:&error]
    其中
    store
    是已添加到协调器的源存储(此操作将删除它,并添加迁移的存储)。这将有效地将
    store
    的内容注入applicationStoreURL的
    NSSQLiteStoreType
    存储区
  • 阿普里卡
    - (NSURL *)supportFilesDirectoryURL {
        NSURL       *result                         = nil;
        NSURL       *applicationSupportDirectoryURL = [[[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask] lastObject];
        NSString    *bundleName                     = [[NSBundle bundleForClass:[self class]] bundleIdentifier];
    
        result = [applicationSupportDirectoryURL URLByAppendingPathComponent:bundleName isDirectory:@YES];
    
        return result;
    }
    
    - (NSURL *) applicationStoreURL {
        NSError             *error                  = nil;
        NSFileCoordinator   *coordinator            = nil;
        __block BOOL        didCreateDirectory      = NO;
        NSURL               *supportDirectoryURL    = [self supportFilesDirectoryURL];
        NSURL               *storeDirectoryURL      = [supportDirectoryURL URLByAppendingPathComponent:@"ApplicationData" isDirectory:YES];
    
        coordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
        [coordinator coordinateWritingItemAtURL:storeDirectoryURL options:NSFileCoordinatorWritingForDeleting error:&error byAccessor:^(NSURL *writingURL){
            NSFileManager   *fileManager    = [[NSFileManager alloc] init];
            NSError         *fileError      = nil;
            if (![fileManager createDirectoryAtURL:writingURL withIntermediateDirectories:YES attributes:nil error:&fileError]){
                [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                    // Handle the error
                }];
            } else {
                // Setting NSURLIsExcludedFromBackupKey on the directory will exclude all items in this directory
                // from backups. It will also prevent them from being purged in low space conditions. Because of this,
                // the files inside this directory should be purged by the application.
                [writingURL setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:&fileError];
                didCreateDirectory = YES;
            }
        }];
    
        // See NSFileCoordinator.h for an explanation.
        if (didCreateDirectory == NO){
            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                // Handle the error.
            }];
        }
    
        return [NSURL URLWithString:@"Application.sqlite" relativeToURL:storeDirectoryURL ];
    }
    
        if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:@"Application" URL:[self applicationStoreURL] options:nil error:&error]) {
            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                // Handle the error.
            }];
        }
    
        if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:@"User" URL:[self userStoreURL] options:nil error:&error]) {
            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                // Handle the error.
            }];
        }