iOS – 用MagicalRecordpipe理两个CoreData模型

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

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

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

更好的解决scheme是创build第二个模型,只为新的实体:种子数据库将永远不会改变,第一个模型可以照顾它的版本,无论新的模型。 这两个模型之间不需要任何关系。

在现有的模型之上,我也使用了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可行吗? 我已经通过它的文档,但可以find有用的东西。

非常感谢,DAN

UPDATE

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

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

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

以下是如何创build一个协调器中的两个持久性存储: https : //stackoverflow.com/a/24022978/2515181

为了澄清,如果我可以只有一个单一的SQLite文件,这将是伟大的,但这样做,我不得不产生种子数据库每次模型的变化。

我不想进入一个很长的答案,因为我不使用MagicalRecord,并且我没有IDEA如何pipe理模型configuration。

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

苹果的文档是一个很好的起点,networking上有很多文章和例子 。

编辑

OK DAN,这是一个有点人为的(但简单的)使用多个configuration的例子。 你应该能够复制/粘贴到一个testing文件并运行它,这应该让你跟踪发生了什么,并得到一个基本的了解。

请注意,这不是我build议编写生产代码和testing(我也不build议忽略错误)的方式,但我希望这有助于解释一些事情,并允许您尝试。

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

首先,我们创build一个简单的模型,包含四个实体,我们将在这两个实体中放置两个实体。

 - (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的函数,并创build一些示例实体。 这个函数也检查以确保所有实体都可以被访问。

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

和一个testingfunction…

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