将大数据集导入核心数据(具有多个存储的解决方案)

时间:2013-05-13 12:27:44

标签: ios json core-data import

我知道这个话题已经讨论过,但我正在寻找一个特定的解决方案,这个解决方案已在任何地方讨论过,即使用多个存储而不是一个 - 一个用于默认数据,另一个用于用户输入的数据。

在我的应用程序中,我想为实体X(仅限)预加载大量数据,即20 MB json文件。该模型还包含实体Y和实体Z.我认为最适合我需求的解决方案如下:

  

使用两个sqlite数据库。仅适用于Entity X的一个数据库,可在应用程序的未来版本中替换...而不会影响实体Y和实体Z的数据(毫不费力)。

  • 我该如何实施这样的解决方案?
  • 实用吗?
  • 我必须制作两个型号吗?
  • 如何在这种情况下设置核心数据管理对象上下文?

详情(仅限于案例):

我有两个选择(如建议的那样):

  1. 使用应用程序捆绑json文件并在首次启动应用程序时加载
  2. 生成sqlite数据库,并使用预先填充的数据库发送应用程序
  3. 有了第一个选项,我有以下问题:

    • 应用程序启动会很慢(因为解析一个20 MB的文件然后在核心数据中创建相应的记录需要一些时间。)
    • 一旦使用该文件,就不需要该应用程序正在使用的20 MB空间。我不认为有什么办法摆脱那个文件,是吗?

    有了第二个选项,我有以下问题:

    • 让我们说在我的应用程序的2.0版中,我想更新默认存储。例如,我在1.0版中提供的默认sqlite数据库有一些问题,或者我想添加更多“默认”记录?我有多个实体,用户可能已将数据添加到其他实体。所以,我无法替换sqlite数据库。那么,我该如何更新数据库中的记录呢?

2 个答案:

答案 0 :(得分:0)

我不知道拥有2个数据库是否真的更好,因为你所做的改变主要不仅仅是扩展功能。

对于数据库迁移,您可以使用类似的内容。

首先使用核心数据的内部版本控制系统,并在NSUserDefaults和我的示例中保存当前使用的版本infoDictionary(您连接的.plist文件)。所以你可以先尝试轻量级迁移,然后再修改manuel,如果你的更改不能自动合并。

NSNumber *newDbVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"DBVersion"];
NSNumber *oldDbVersion = [[NSUserDefaults standardUserDefaults] objectForKey:@"DBVersion"];

NSURL *storeUrlOld;
if(!oldDbVersion)
    storeUrlOld = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"default.sqlite"]]; // default path
else
    storeUrlOld = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: [NSString stringWithFormat:@"db_%d.sqlite",[oldDbVersion intValue]]]];

NSURL *storeUrlNew = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: [NSString stringWithFormat:@"db_%d.sqlite",[newDbVersion intValue]]]];

NSString *path = [[NSBundle mainBundle] pathForResource:@"myDB" ofType:@"momd"];
if(oldDbVersion)
    path = [path stringByAppendingPathComponent:[NSString stringWithFormat:@"db_%d.mom", [oldDbVersion intValue]]];

NSURL *momURLOld = [NSURL fileURLWithPath:path];
NSLog(@"mom-path old: %@", path);
NSLog(@"mom-url old: %@", momURLOld);

NSManagedObjectModel *oldManagedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:momURLOld];

// - - -

path = nil;
path = [[NSBundle mainBundle] pathForResource:@"db" ofType:@"momd"];
path = [path stringByAppendingPathComponent:[NSString stringWithFormat:@"db_%d.mom",[newDbVersion intValue]]];

NSURL *momURLNew = [NSURL fileURLWithPath:path];
NSLog(@"mom-path new: %@", path);
NSLog(@"mom-url new: %@", momURLNew);
NSManagedObjectModel *newManagedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:momURLNew];

// # # # # # # # # # # # # # # # # # # # # #
// - - - - Connect with old Database - - - -
// # # # # # # # # # # # # # # # # # # # # #

NSError *error;
NSPersistentStoreCoordinator *persistentStoreCoordinatorOld = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:oldManagedObjectModel];

// Allow inferred migration from the original version of the application.
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                         [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                         [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

if (![persistentStoreCoordinatorOld addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrlOld options:options error:&error]) 
{
    // Handle the error
    NSLog(@"Failed to add old persistent store: %@", [error localizedDescription]);
    NSArray* detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];

    if(detailedErrors != nil && [detailedErrors count] > 0) 
    {
        for(NSError* detailedError in detailedErrors) {
            NSLog(@"  DetailedError: %@", [detailedError userInfo]);
        }
    }
    else 
    {
        NSLog(@"ERROR persistentStoreCoordinator: %@", [error userInfo]);
    }
    return;
}

NSManagedObjectContext *oldManagedObjectContext = [[NSManagedObjectContext alloc] init];
[oldManagedObjectContext setPersistentStoreCoordinator:persistentStoreCoordinatorOld];

// # # # # # # # # # # # # # # # # # # # # #
// - - - - Connect with new Database - - - -
// # # # # # # # # # # # # # # # # # # # # #

NSPersistentStoreCoordinator *persistentStoreCoordinatorNew = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: newManagedObjectModel];

if (![persistentStoreCoordinatorNew addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrlNew options:options error:&error]) 
{
    // Handle the error
    NSLog(@"Failed to add new persistent store: %@", [error localizedDescription]);
    NSArray* detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];

    if(detailedErrors != nil && [detailedErrors count] > 0) 
    {
        for(NSError* detailedError in detailedErrors) {
            NSLog(@"  DetailedError: %@", [detailedError userInfo]);
        }
    }
    else 
    {
        NSLog(@"ERROR persistentStoreCoordinator: %@", [error userInfo]);
    }
    return;
}    

NSManagedObjectContext *newManagedObjectContext = [[NSManagedObjectContext alloc] init];
[newManagedObjectContext setPersistentStoreCoordinator:persistentStoreCoordinatorNew];
managedObjectContext = newManagedObjectContext;

// # # # # # # # # # # # # # # # # # # # # # # #
// - - - Transfere data from old DB to new - - -
// # # # # # # # # # # # # # # # # # # # # # # #

// - - -

// # # # # # # # # #
// - - - Users - - -
// # # # # # # # # # 

NSString *entityName = @"User";
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:oldManagedObjectContext];
[request setEntity:entity];
NSString *predicateFormat ;
NSPredicate *predicate;
error = nil;

NSMutableArray *mutableFetchResultsUsers = [NSMutableArray arrayWithArray: [oldManagedObjectContext executeFetchRequest:request error:&error]];

if (mutableFetchResultsUsers == nil) {
    // Handle the error.
}
NSLog(@"Users: %@", mutableFetchResultsUsers);
for(User *user in mutableFetchResultsUsers)
{
    NSLog(@"%@, %@, %@",user.userLogin,user.userDomain, user.serverAddress);
    User *userNew = [[DatabaseFactory sharedInstance] newObject:@"User"];
[...] // do here integration
    userNew.attibute = user.attribute;

    [self saveContext];
}
[request release];
request = nil;

// next one
希望我能帮助你一点;)

答案 1 :(得分:0)

我最终使用了2个持久存储。一个用于“readwrite”数据库,一个用于“readonly”(种子)数据库。在该应用程序的未来版本中,我可以毫无问题地发布更新的种子数据库。

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }

    // Define the Core Data version migration options
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                             [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
                             nil];

    // Attempt to load the persistent store
    NSError *error = nil;
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];

    // Create the default/ user model persistent store
    {
        NSString *storeFileName = ...;
        NSString *configuration = @"Readwite";
        NSURL *storeURL = [[self applicationLocalDatabaseDirectory] URLByAppendingPathComponent:storeFileName];

        if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
                                                       configuration:configuration
                                                                 URL:storeURL
                                                             options:options
                                                               error:&error]) {
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }
    }

    // Create the seed data persistent store
    {
        NSURL *seedDataURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"SeedData" ofType:@"sqlite"]];
        NSString *configuration = @"SeedData";

        if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
                                                       configuration:configuration
                                                                 URL:seedDataURL
                                                             options:options
                                                               error:&error]) {
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort();
            abort();
        }
    }

    // Developer's Note:
    // Instead of creating a single store, we created two persistent stores in an almost identical manner.
    // The only difference is that we explicitly named the configuration for the store to use, instead of
    // passing nil for the configuration parameter. Note that the configurations were set in xcdatamodeld file.

    return _persistentStoreCoordinator;
}

参考:

Can multiple (two) persistent stores be used with one object model, while maintaining relations from one to the other?