iOS - 使用MagicalRecord管理两个CoreData模型 [英] iOS - Managing two CoreData models with MagicalRecord

查看:187
本文介绍了iOS - 使用MagicalRecord管理两个CoreData模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用MagicalRecord处理CoreData模型,这可能会在未来版本化。

I'm using MagicalRecord to work with a CoreData model, which is likely to be versioned in the future.

现在我需要添加一个pre一个实体约80000个对象的人口数据库;这个数据是静态的,我不期望它会改变。

Now I need to add to my app a pre-populated database with one entity of about 80000 objects; this data is static and I'm not expected it will ever change.

如果我添加这个实体到现有的模型,我需要每次生成一个新的种子数据库模型改变,增加了项目的复杂性。

If I added this entity to the existing model I would need to generate a new seed db every time the model changes, increasing the project complexity.

一个更好的解决方案是创建一个第二个模型,只是为新的实体:种子数据库永远不会改变,第一个模型可以照顾其版本控制,而不管新模型。

A better solution would be creating a second model, just for the new entity: the seed db will never change and the first model could take care of its versioning regardless of the new model. No relation between the two models is required.

在现有模型的基础上,我也使用RestKit,下面是如何设置一切:

On top of the existing model I'm using RestKit too and here's how everything is setup:

[MagicalRecord setupAutoMigratingCoreDataStack];
RKManagedObjectStore *managedObjectStore =
    [[RKManagedObjectStore alloc] initWithPersistentStoreCoordinator:
        [NSPersistentStoreCoordinator MR_newPersistentStoreCoordinator]];
self.objectManager.managedObjectStore = managedObjectStore;
[managedObjectStore createManagedObjectContexts];
// bind RK with MagicalRecord
[NSManagedObjectContext MR_setRootSavingContext:
    managedObjectStore.persistentStoreManagedObjectContext];
[NSManagedObjectContext MR_setDefaultContext:
    managedObjectStore.mainQueueManagedObjectContext];
managedObjectStore.managedObjectCache = [[RKFetchRequestManagedObjectCache alloc] init];

新模型不会与RestKit一起使用。

The new model will not be used with RestKit.

这是否可行的MagicalRecord?
我已经通过其文档,但可以找到任何有用的。

Is this feasible with MagicalRecord? I've been through its documentation but could find anything useful.

非常感谢,
DAN

Many thanks, DAN

UPDATE

让我们有一个包含4个实体(Foo,Bar,Blarg,Baz) 。
模型编辑器具有无法删除的默认配置,因此我们只能添加两个新配置(SeedConfiguration和UserConfiguration),将Foo添加到第一个,将另外三个添加到第二个。
两个配置应保存在seed.sqlite和user.sqlite中。
在这一点上,我想运行一个脚本,它使用数千个Foo对象填充seed.sqlite:一旦生成此文件将被放入项目资源,并在启动时复制到应用程序目录中; user.sqlite将在运行时生成,并用于管理用户信息。

Let's have a db model with 4 entities (Foo, Bar, Blarg, Baz) created with the xcode editor. The model editor has a Default configuration which cannot be removed, so we can only add two new configurations (SeedConfiguration and UserConfiguration), add Foo to the first and the other three to the second. The two configurations should be saved in seed.sqlite and user.sqlite. At this point I'd like to run a script which populates seed.sqlite with thousands of Foo objects: once generated this file will be put in the project resources and copied in the app directory at startup; user.sqlite will be instead generated at runtime and used to manage the user info.

当我以脚本模式启动应用程序来填充seed.sqlite时, sqlite文件正确创建,但它们都包含所有的实体,而我期望在seed.sqlite和Bar,Blarg,Baz在user.sqlite中找到Foo。

When I launch the app in "script" mode to populate seed.sqlite, the two sqlite files are correctly created but both of them contain all the entities, whereas I would expect to find Foo in seed.sqlite and Bar, Blarg, Baz in user.sqlite.

我应该插入Foo对象,并复制结果seed.sqlite,即使它包含所有其他(空)实体?

Should I insert the Foo objects and copy the resulting seed.sqlite even if it contains all the other (empty) entities?

这是如何两个持久存储在一个单一的协调器可以创建:
http://stackoverflow.com/a/24022978/2515181

Here's how two persistence stores in one single coordinator can be created : http://stackoverflow.com/a/24022978/2515181

为了澄清,如果我可以只有一个单一的sqlite文件,这将是巨大的,但这样做,我必须生成种子数据库每次模型更改。

For the sake of clarification if I could just have one single sqlite file it would be great, but doing so I'd have to generate the seed db every time the model changes.

推荐答案

我不想进入一个很长的答案,因为我不使用MagicalRecord,我没有IDEA如何管理模型配置。

I didn't want to get into a long answer because I do not use MagicalRecord, and I have NO IDEA how it manages model configurations.

话虽如此,你想要解决这个问题的方法是使用模型配置和多个存储文件。这个问题是很好理解和记录。

That being said, the way you want to approach this problem is by using model configurations and multiple store files. The problem is both well understood and well documented.

Apple的文档是一个很好的起点,还有网络上的众多文章和示例

Apple's documentation is a good starting point, and there are numerous articles and examples on the web.

EDIT

OK DAN,这里是一个有点勉强(但简单)的使用多个配置的例子。您应该可以将其复制/粘贴到测试文件并运行,这应该可以帮助您跟踪发生了什么,并得到一个基本的了解。

OK DAN, here is a somewhat contrived (but simple) example for using multiple configurations. You should be able to copy/paste this into a test file and run it, which should allow you to trace what's going on and get a basic understanding.

注意,这不是我建议编写生产代码或测试(我也不建议忽略错误),但我希望这有助于解释一些事情,并允许你进行实验。

Note, that this is not the way I would advise writing production code nor tests (I also don't advise ignoring errors), but I hope this helps explain some things a bit and allows you to experiment.

我将代码分解成几个帮助方法,希望能够更好地解释。

I broke the code into several helper methods to hopefully better explain.

首先,我们创建一个简单的模型,

First, let's create a simple model, with four entities, where we will put two into each configuration.

- (NSManagedObjectModel *)makeConfigurationModel {
    NSAttributeDescription *nameAttr = [[NSAttributeDescription alloc] init];
    nameAttr.name = @"name";
    nameAttr.attributeType = NSStringAttributeType;

    NSEntityDescription *foo = [[NSEntityDescription alloc] init];
    foo.name = @"Foo";
    foo.properties = @[[nameAttr copy]];
    NSEntityDescription *bar = [[NSEntityDescription alloc] init];
    bar.name = @"Bar";
    bar.properties = @[[nameAttr copy]];

    NSEntityDescription *blarg = [[NSEntityDescription alloc] init];
    blarg.name = @"Blarg";
    blarg.properties = @[[nameAttr copy]];
    NSEntityDescription *baz = [[NSEntityDescription alloc] init];
    baz.name = @"Baz";
    baz.properties = @[[nameAttr copy]];


    NSManagedObjectModel *model = [[NSManagedObjectModel alloc] init];
    model.entities = @[foo, bar, blarg, baz];
    [model setEntities:@[foo, bar] forConfiguration:@"One"];
    [model setEntities:@[blarg, baz] forConfiguration:@"Two"];

    return model;
}

接下来,一个函数将两个商店分配给PSC,实体。此函数还会检查以确保所有实体均可访问。

Next, a function to assign both stores to a PSC, and create some example entities. This function also checks to make sure all entities can be accessed.

- (void)setupDatabaseWithModel:(NSManagedObjectModel*)model
                        store1:(NSURL*)store1URL
                        store2:(NSURL*)store2URL {
    @autoreleasepool {
        NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc]
            initWithManagedObjectModel:model];
        [psc addPersistentStoreWithType:NSSQLiteStoreType
                          configuration:@"One"
                                    URL:store1URL
                                options:nil
                                  error:NULL];
        [psc addPersistentStoreWithType:NSSQLiteStoreType
                          configuration:@"Two"
                                    URL:store2URL
                                options:nil
                                  error:NULL];
        NSManagedObjectContext *moc = [[NSManagedObjectContext alloc]
            initWithConcurrencyType:NSMainQueueConcurrencyType];
        moc.persistentStoreCoordinator = psc;

        // Add some entities...
        NSArray *entityNames = @[@"Foo", @"Bar", @"Blarg", @"Baz"];
        for (NSString *e in entityNames) {
            NSManagedObject *obj =
                [NSEntityDescription insertNewObjectForEntityForName:e
                                              inManagedObjectContext:moc];
            [obj setValue:[NSString stringWithFormat:@"%@ 1", e] forKey:@"name"];
        }
        [moc save:NULL];

        // Should have all of them in this MOC...
        for (NSString *e in entityNames) {
            NSFetchRequest *fetchRequest = [NSFetchRequest
                fetchRequestWithEntityName:e];
            NSArray *result = [moc executeFetchRequest:fetchRequest error:NULL];
            XCTAssertEqual(1, result.count);
            NSManagedObject *obj = [result firstObject];
            XCTAssertEqualObjects(([NSString stringWithFormat:@"%@ 1", e]),
                                  [obj valueForKey:@"name"]);
        }
    }
}

某些实体是(或不在)商店中。

And a function to check that certain entities are (or are not) in the store.

- (void)checkStore:(NSURL*)storeURL
             model:(NSManagedObjectModel*)model
           present:(NSArray*)present
        notPresent:(NSArray*)notPresent {
    @autoreleasepool {
        NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc]
            initWithManagedObjectModel:model];
        [psc addPersistentStoreWithType:NSSQLiteStoreType
                          configuration:nil
                                    URL:storeURL
                                options:nil
                                  error:NULL];
        NSManagedObjectContext *moc = [[NSManagedObjectContext alloc]
            initWithConcurrencyType:NSMainQueueConcurrencyType];
        moc.persistentStoreCoordinator = psc;

        for (NSString *e in present) {
            NSFetchRequest *fetchRequest = [NSFetchRequest
                fetchRequestWithEntityName:e];
            NSArray *result = [moc executeFetchRequest:fetchRequest error:NULL];
            XCTAssertEqual(1, result.count);
            NSManagedObject *obj = [result firstObject];
            XCTAssertEqualObjects(([NSString stringWithFormat:@"%@ 1", e]),
                                  [obj valueForKey:@"name"]);
        }
        for (NSString *e in notPresent) {
            NSFetchRequest *fetchRequest = [NSFetchRequest
                fetchRequestWithEntityName:e];
            NSArray *result = [moc executeFetchRequest:fetchRequest error:NULL];
            XCTAssertEqual(0, result.count);
        }
    }
}

URL

static void removeURL(NSURL ** url) {
    [[NSFileManager defaultManager] removeItemAtURL:*url error:NULL];
}

还有一个测试函数...

And a test function...

- (void)testConfigurations {
    __attribute__((cleanup(removeURL))) NSURL * __autoreleasing dirURL =
        [[[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory
                                                inDomain:NSUserDomainMask
                                       appropriateForURL:nil
                                                  create:YES
                                                    error:NULL]
            URLByAppendingPathComponent:[[NSUUID UUID] UUIDString]];
    [[NSFileManager defaultManager] createDirectoryAtURL:dirURL
                             withIntermediateDirectories:YES
                                              attributes:nil
                                                   error:NULL];

    NSManagedObjectModel *model = [self makeConfigurationModel];
    NSURL *store1URL = [dirURL URLByAppendingPathComponent:@"store1"];
    NSURL *store2URL = [dirURL URLByAppendingPathComponent:@"store2"];
    [self setupDatabaseWithModel:model store1:store1URL store2:store2URL];
    [self checkStore:store1URL
               model:model
             present:@[@"Foo", @"Bar"]
          notPresent:@[@"Blarg", @"Baz"]];
    [self checkStore:store2URL
               model:model
             present:@[@"Blarg", @"Baz"]
          notPresent:@[@"Foo", @"Bar"]];
}

这篇关于iOS - 使用MagicalRecord管理两个CoreData模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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