2015-10-16 26 views
0

我正在使用MagicalRecord与CoreData模型一起工作,该模型将来可能会进行版本控制。iOS - 使用MagicalRecord管理两个CoreData模型

现在我需要向我的应用程序添加一个预先填充的数据库,其中包含约80000个对象的实体;这个数据是静态的,我不希望它会改变。

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

更好的解决方案是为新实体创建第二个模型:种子数据库永远不会改变,第一个模型可以处理它的版本控制,而不管新模型如何。这两种模型之间不需要任何关系。

在我使用过RestKit这里现有的模型上的一切是如何设置:

[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使用。

MagicalRecord可行吗? 我已经通过它的文档,但可以找到有用的东西。

非常感谢, DAN

UPDATE

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

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

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

下面是一个单一的协调两种持久性存储如何创建: https://stackoverflow.com/a/24022978/2515181

为了清楚起见,如果我可以有一个单一的SQLite文件,这将是巨大的,但这样做我不得不每次模型更改时生成种子数据库。

+0

这是什么型号的配置都是。 –

+0

他们应该如何使用?这是一个类似于我的场景:http://blog.atwam.com/blog/2012/05/11/multiple-persistent-stores-and-seed-data-with-core-data其中建议使用两种模式合并到一个NSPersistentStoreCoordinator中。 – DAN

+0

我们中的一个人错过了一些东西。 “种子”文件应该只包含Foo实体。当你说它包含“空”实体时,你是什么意思?是否有一堆具有默认值或实体的实体?如果是这样,也许你的设置不正确。你怎么知道在“种子”文件中有Bar,Blarg和Baz实体?你如何获得它你从“种子”数据库中获取所有“酒吧”实体?你确定你不只是混淆了模型定义每个实体的事实,而且数据库中没有实际的实体吗? –

回答

1

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

这就是说,你想要解决这个问题的方式是使用模型配置和多个存储文件。这个问题既好理解又有据可查。

Apple's documentation是一个很好的起点,并且有numerous articles and examples on the web

EDIT

行DAN,这里是用于使用多个配置有点做作(但简单)的例子。您应该能够将其复制/粘贴到测试文件中并运行它,这应该允许您追踪正在发生的事情并获得基本的理解。

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

我把代码分解成了几个辅助方法,希望能更好地解释。

首先,我们创建一个简单模型,其中包含四个实体,我们将在这两个实体中放入两个参数。

- (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,并创建一些示例实体。该功能还检查以确保可以访问所有实体。

- (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"]); 
     } 
    } 
} 

还有一个函数来检查某些实体是否在商店中(或不在)。

- (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]; 
} 

和测试功能...

- (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"]]; 
} 
+0

嗨@Jody,我设法创建了两种不同的配置,并将它们保存在两个不同的持久存储协调器中。我看到的是,两个sqlite文件都包含所有的实体。我希望每个sqlite文件只包含其实体。 – DAN

+0

你不需要不同的PSC。这是商店协调员的要点。它管理多个商店。这些配置允许您将实体分配给特定的商店。您应该可以通过单个PSC和多个商店来完成此操作。如果你不依赖MR,我可能会提供更多的帮助,但我不知道它是什么或不在做什么,所以我只会猜测。 –

+0

我最后的评论是错误的,我实际上是用一个协调器创建两个持久性存储(请参阅我在原始问题中的更新)。我们现在可以忘记MR,它只是核心数据之上的一层,稍后我会照顾它。一切似乎工作,除非像我说过的所有实体都出现在两个SQLite文件,即使在模型编辑器有两种配置。 – DAN

相关问题