2015-10-16 67 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

相關問題