什么是合并两个iOS核心数据持久存储的有效方式? [英] What is an efficient way to Merge two iOS Core Data Persistent Stores?

查看:262
本文介绍了什么是合并两个iOS核心数据持久存储的有效方式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我们正在开发的应用程序中,我们使用Core Data和sqlite后备存储来存储我们的数据。我们的应用程序的对象模型是复杂的。此外,我们的应用程序提供的总数据量太大,无法适应iOS(iPhone / iPad / iPod Touch)应用程序包。因为我们的用户通常只对数据的一个子集感兴趣,所以我们对数据进行了分区,使得应用程序与一个子集(尽管约100 MB)的数据对象应用程序包。我们的用户可以选择从服务器下载额外的数据对象(大小〜5 MB到100 MB),他们通过iTunes应用内购买支付额外的内容。

增量数据文件(存在于sqlite后备存储中)使用与捆绑软件附带的数据相同的xcdatamodel版本;对象模型有零更改。增量数据文件作为gzip压缩的sqlite文件从我们的服务器下载。我们不想通过应用程序发送增量内容来膨胀我们的应用程序包。此外,我们不想依赖于对Web服务的查询(因为复杂的数据模型)。

我们测试了从我们的服务器下载增量sqlite数据。我们已经能够将下载的数据存储添加到应用程序的sharedStoreCoordinator。

In our app under development we are using Core Data with a sqlite backing store to store our data. The object model for our app is complex. Also, the total amount of data served by our app is too large to fit into an iOS (iPhone/iPad/iPod Touch) app bundle. Because of the fact that our users are, typically, interested only in a subset of the data, we've partitioned our data in such a way that the app ships with a subset (albeit, ~100 MB) of the data objects in the app bundle. Our users have the option of downloading additional data objects (of size ~5 MB to 100 MB) from our server after they pay for the additional contents through iTunes in-app purchases.   The incremental data files (existing in sqlite backing stores) use the same xcdatamodel version as the data that ships with the bundle; there is zero changes to the object model. The incremental data files are downloaded from our server as a gzipped sqlite files. We don't want to bloat our app bundle by shipping the incremental contents with the app. Also, we don't want to rely on queries over webservice (because of the complex data model).   We've tested the download of the incremental sqlite data from our server. We have been able to add the downloaded data store to the app's shared persistentStoreCoordinator.  

{
       NSError *error = nil;
       NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                                [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, 
                                [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

       if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:defaultStoreURL options:options error:&error])
       {            
           NSLog(@"Failed with error:  %@", [error localizedDescription]);
           abort();
       }    

       // Check for the existence of incrementalStore
       // Add incrementalStore
       if (incrementalStoreExists) {
           if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:incrementalStoreURL options:options error:&error])
           {            
               NSLog(@"Add of incrementalStore failed with error:  %@", [error localizedDescription]);
               abort();
           }    
       }
 }


但是,这样做有两个问题。

  However, there are two problems with doing it this way.


  1. 数据获取结果(例如,使用NSFetchResultController)显示
    数据从追加到来自defaultStoreURL的
    数据末尾的incrementalStoreURL。

  2. 某些对象是重复的。在我们的数据模型中有许多具有
    只读数据的实体;

理想情况下,我们希望核心数据能够合并第一个persistStore对象图从一个(在数据下载时两个存储的数据之间没有共享关系)。此外,我们想删除重复的对象。
在网上搜索,我们看到了一些人试图做我们正在做的事情的一些问题 - 例如此答案此答案。我们已阅读 Marcus Zarra的导入博客Core Data中的大数据集。然而,我们看到的解决方案都没有为我们工作。我们不想手动读取并将数据从增量存储保存到默认存储,因为我们认为这将非常缓慢,并且在电话上容易出错。有没有更有效的方式来进行合并?

Ideally, we would like Core Data to merge the object graphs from the two persistent stores into one (there are no shared relationships between data from the two stores at the time of the data download). Also, we would like to remove the duplicate objects. Searching the web, we saw a couple of questions by people attempting to do the same thing we are doing--such as this answer and this answer. We've read Marcus Zarra's blog on importing large data sets in Core Data. However, none of the solutions we've seen worked for us. We don't want to manually read and save the data from the incremental store to the default store as we think this will be very slow and error prone on the phone. Is there a more efficient way of doing the merge?

我们试图通过实现手动迁移来解决这个问题,如下所示。但是,我们还没有能够成功地使合并发生。我们不太清楚上面提到的答案1和2建议的解决方案。 Marcus Zarra的博客解决了我们在将我们的大型数据集导入到iOS中时所遇到的一些问题。

We've attempted to solve the problem by implementing a manual migration as follows. However, we haven't been able to successfully get the merge to happen. We are not really clear on the solution suggested by answers 1 and 2 referenced above. Marcus Zarra's blog addressed some of the issues we had at the outset of our project importing our large dataset into iOS.

{
       NSError *error = nil;
       NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                                [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, 
                                [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];        

       NSMigrationManager *migrator = [[NSMigrationManager alloc] initWithSourceModel:__managedObjectModel destinationModel:__managedObjectModel];
       if (![migrator migrateStoreFromURL:stateStoreURL
                                type:NSSQLiteStoreType 
                             options:options 
                    withMappingModel:nil
                    toDestinationURL:destinationStoreURL 
                     destinationType:NSSQLiteStoreType 
                  destinationOptions:nil 
                               error:&error])
       {
           NSLog(@"%@", [error userInfo]);
           abort();
       }
}


似乎作者的回答1结束从增量存储读取他的数据并保存到默认存储。也许,我们误解了第1和第2条建议的解决方案, 2.我们的数据大小可能阻止我们手动读取和重新插入我们的增量数据到默认存储。我的问题是:什么是最有效的方式来获取对象图从两个persistentStores(具有相同的objectModel)合并到一个persistentStore?

  It seems that the author of answer 1 ended up reading his data from the incremental store and saving to the default store. Perhaps, we've misunderstood the solution suggested by both articles 1 & 2. The size of our data may preclude us from manually reading and re-inserting our incremental data into the default store. My question is: what is the most efficient way to get the object graphs from two persistentStores (that have the same objectModel) to merge into one persistentStore?

当我们向对象图表添加新的实体属性或修改关系时,自动迁移效果非常好。有没有简单的解决方案将类似的数据合并到相同的持久存储,将足够的弹性足以停止和恢复 - 自动迁移完成?

Automatic migration works pretty well when we add new entity attributes to object graphs or modify relationships. Is there a simple solution to merging similar data into the same persistent store that will be resilient enough to stop and resume--as automatic migration is done?

推荐答案

经过多次尝试,我想出了如何使这项工作。秘密是首先创建增量存储数据,而不包含只读实体的任何数据。在不将增量存储中的只读数据保留的情况下,这些实体实例将在数据迁移和合并之后被复制。因此,应该创建没有这些只读实体的增量存储。默认存储将是具有它们的唯一存储。

After several attempts, I've figured out how to make this work. The secret is to first create the incremental store data without any data for the read-only entities. Without leaving read-only data out of the incremental stores, the entities instances for these would get duplicated after the data migration and merge. Hence, the incremental stores should be created without these read-only entities. The default store will be the only store that has them.

例如,我的数据模型中有实体Country和State。我需要在我的对象图中只有一个Country和State的实例。我将这些实体保留在增量存储中,并仅在默认存储中创建它们。我使用Fetched属性松散地链接我的主要对象图形到这些实体。我创建了所有实体实例在我的模型中的默认存储。增量存储在数据创建完成后没有只读实体(即我的情况下的国家和州)开始或删除它们。

For example, I had entities "Country" and "State" in my data model. I needed to have only one instance of Country and State in my object graph. I kept these entities out of incremental stores and created them only in the default store. I used Fetched Properties to loosely link my main object graph to these entities. I created the default store with all the entity instances in my model. The incremental stores either didn't have the read-only entities (i.e., Country and State in my case) to start with or deleted them after data creation is completed.

下一步是在应用程序启动期间将增量存储添加到自己的persistentStoreCoordinator(与我们要将所有内容迁移到的默认存储的协调器不同)。

Next step is to add the incremental store to it's own persistentStoreCoordinator (not the same as the coordinator for the default store that we want to migrate all contents to) during application startup.

最后一步是在增量存储上调用migratePersistentStore方法,将其数据合并到主(即默认)存储。 Presto!

The final step is to call migratePersistentStore method on the incremental store to merge its data to the main (i.e., default) store. Presto!

以下代码片段说明了上面提到的最后两个步骤。我做了这些步骤,使我的设置合并增量数据到主数据存储工作。

The following code fragment illustrates the last two steps I mentioned above. I did these steps to make my setup to merge incremental data into a main data store to work.

{
    NSError *error = nil;
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
    [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, 
    [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

    if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:defaultStoreURL options:options error:&error])
    {            
        NSLog(@"Failed with error:  %@", [error localizedDescription]);
        abort();
    }    

    // Check for the existence of incrementalStore
    // Add incrementalStore
    if (incrementalStoreExists) {

        NSPersistentStore *incrementalStore = [_incrementalPersistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:incrementalStoreURL options:options error:&error];
        if (!incrementalStore)
        {
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }    

        if (![_incrementalPersistentStoreCoordinator migratePersistentStore:incrementalStore
            toURL:_defaultStoreURL
            options:options
            withType:NSSQLiteStoreType
            error:&error]) 
        {
            NSLog(@"%@", [error userInfo]);
            abort();

        }

        // Destroy the store and store coordinator for the incremental store
        [_incrementalPersistentStoreCoordinator removePersistentStore:incrementalStore error:&error];
        incrementalPersistentStoreCoordinator = nil;
        // Should probably delete the URL from file system as well
        //
    }
}

这篇关于什么是合并两个iOS核心数据持久存储的有效方式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆