2012-06-07 34 views
16

Tôi đang gặp sự cố khi di chuyển nhẹ khi di chuyển từ một cửa hàng được xác định bởi hai tệp xcdatamodel riêng biệt.Dữ liệu chính - di chuyển nhẹ và nhiều tệp mô hình dữ liệu lõi (xcdatamodel)

Trong phiên bản 1.0 của ứng dụng, tôi đã có các mô hình được chia nhỏ thành mô hình phân tích, mô hình A và mọi thứ khác trong mô hình B. Khi biên dịch, các mô hình sẽ được nhóm lại với nhau và mọi thứ diễn ra suôn sẻ.

Khi làm việc trên phiên bản mới, 1.1, tôi đã nâng cấp model-B bằng cách thêm phiên bản mô hình mới vào model-B và thiết lập phiên bản mới đó là đang hoạt động.

Sự cố phát sinh khi nâng cấp từ 1.0 lên 1.1. Có vẻ như Core Data kiểm tra lưu trữ mô hình trên đĩa (được tạo bởi phiên bản 1.0) và tìm mô hình mô tả nó nhưng không thể tìm thấy mô hình SINGLE xác định toàn bộ cửa hàng (model-A chỉ bao gồm phân tích và mô hình B mọi thứ khác), do đó, nó ném lỗi "Không thể tìm thấy mô hình cho lưu trữ nguồn".

Có ai tìm thấy giải pháp để tách các mô hình nhưng vẫn cho phép nâng cấp + di chuyển nhẹ để hoạt động mà không gặp rắc rối khi xác định di chuyển tùy chỉnh không?

Dưới đây là đoạn mã sử dụng để tải mô hình:

NSArray *modelNames = [NSArray arrayWithObjects:@"model-A", @"model-B", nil]; 
    NSMutableArray *models = [NSMutableArray array]; 
    for (NSString *name in modelNames) 
    { 
     LogInfo(@"loading model %@", name); 
     NSURL *modelURL = [[NSBundle mainBundle] URLForResource:name withExtension:@"momd"]; 
     NSManagedObjectModel *model = [[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL] autorelease]; 
     [models addObject:model]; 
    } 

    // combine all the separate models into one big one 
    objectModel = [[NSManagedObjectModel modelByMergingModels:models] retain]; 

    NSURL *documentsDirectory = [NSURL fileURLWithPath:[SuperFileManager documentsDirectory] isDirectory:YES]; 
    NSURL *storeURL = [documentsDirectory URLByAppendingPathComponent:@"database.sqlite"]; 
    NSError *error = nil; 

    coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:objectModel]; 
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: 
                [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, 
                [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, 
                nil]; 

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

Trả lời

8

Sau khi tham dự phòng thí nghiệm WWDC 2012 và gặp nhóm Core Data, có vẻ như bạn buộc phải đặt tất cả thông tin mô hình của mình vào một xcdatamodel đơn lẻ. CoreData không đủ thông minh để kiểm tra các cửa hàng hiện có của nó như là một sự kết hợp của các cửa hàng tạo ra nó và vẫn còn trên đĩa. Như C. Roald đã chỉ ra, bạn có thể thực hiện một số xử lý trên các tệp xcdatamodel cũ, nhưng thật đáng buồn là Core Data không xử lý điều này một cách trang nhã hơn.

+0

Mọi cập nhật về điều này? – codepushr

+0

@codingrogue - tiếc là không. Nhóm tôi đang làm việc vào thời điểm bị bỏ rơi bằng cách sử dụng Dữ liệu cốt lõi và tôi đã chuyển sang lập trình Android. Lấy làm tiếc. :/ – Mark

0

Cách tốt nhất để nâng cấp mô hình Core Data của bạn là thêm một phiên bản. Nếu bạn không làm điều đó, bạn sẽ bị hư mất trong các sự cố, cập nhật hiểm họa và những thứ như thế.

Thêm phiên bản mới thực sự khá dễ dàng. Bạn chọn tệp datamodel và chọn 'Editor> Add model version'. Điều này sẽ cho phép bạn thêm một phiên bản cơ sở dữ liệu mới dựa trên mô hình trước đó. Sau đó, bạn cần đặt mô hình dữ liệu hiện tại thành mới nhất: http://cl.ly/2h1g301b0N143t0b1k2K

iO sẽ tự động di chuyển dữ liệu khi cài đặt phiên bản mới.

hy vọng điều này sẽ hữu ích.

+3

này hoạt động tốt khi bạn có một xcdatamodel duy nhất. Nếu bạn có nhiều và bạn nâng cấp một trong số đó, Dữ liệu cốt lõi không thể hòa giải mọi thứ. Sau khi tham dự một WWDC 2012 phòng thí nghiệm, có vẻ như bạn về cơ bản buộc phải đặt tất cả các thông tin mô hình của bạn trong một xcdatamodel duy nhất và làm như bạn đề nghị! – Mark

8

Tôi cũng gặp sự cố này. Tôi mất vài giờ cố gắng tìm ra WTF - rất bực bội.

Tôi tin rằng cách dễ nhất để giải quyết vấn đề này là:

  1. Pick mà mô hình bạn đang giữ - nói ModelB - và tạo ra một phiên bản mới cho nó dựa trên phiên bản công bố. Tôi sẽ gọi phiên bản được xuất bản ModelBv1 và phiên bản mới ModelBv1_merge.

  2. Mở nội dung Tệp XML cho ModelAv1 và ModelBv1_merge trong trình chỉnh sửa văn bản (ví dụ: ModelA.xcdatamodeld/ModelAv1.xcdatamodel/contentsModelB.xcdatamodeld/ModelBv1_merge.xcdatamodel/contents) và hợp nhất XML theo cách thủ công. Giản đồ rất đơn giản - chỉ cần sao chép các phần tử <entity> và hợp nhất thành phần <elements> (vào tệp nội dung _merge) và bạn đã hoàn tất.

  3. Mở tệp nội dung cho ModelBv2 mới của bạn và nhập lại nội dung ModelA vào đó.

  4. Xóa ModelA khỏi tệp dự án của bạn.

Kiểm tra trong Xcode rằng ModelBv1_merge và ModelBv2 trông lành mạnh và chứa mọi thứ bạn mong đợi (liên kết giữa Mẫu A và Mẫu B cũ).Xây dựng và bạn nên làm.

(Tôi nghĩ rằng điều này có một cảnh báo "cung cấp cả hai tệp nội dung được viết bởi cùng một phiên bản Xcode", nhưng tôi nghĩ rằng nếu bạn có tệp nội dung cũ thì phải dễ dàng làm cho Xcode viết lại nó bằng cách tạo Thay đổi tầm thường ở đâu đó.)

+0

Cách Hacktastic vẫn giữ được 2 tệp mô hình dữ liệu (ngay cả khi chỉ tạm thời! Cảm ơn! :) – Mark

+0

Tuyệt vời. Đã lưu thịt xông khói của tôi. Cảm ơn – Darren

+0

Xin chào, cách này đang làm việc tuyệt vời tại giả lập nhưng nó không hoạt động ở thiết bị ?? –

5

Tôi có một kịch bản trong đó mô hình ứng dụng của tôi thu được sáp nhập nhiều mô hình, và tôi quản lý để có một loại di cư nhẹ tự động theo cách này:

NSError* error = nil; 
NSURL *documentsDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; 
NSURL *storeURL = [documentsDirectory URLByAppendingPathComponent:@"db.sqlite"]; 
NSString* storePath = [storeURL path]; 
NSLog(@"Store URL: %@", storeURL); 
if([[NSFileManager defaultManager] fileExistsAtPath:storePath]){ 
    // Load store metadata (this will contain information about the versions of the models this store was created with) 
    NSDictionary *storeMeta = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:nil URL:storeURL error:&error]; 
    if(storeMeta){ 
     // Get the current model, merging all the models in the main bundle (in their current version) 
     NSManagedObjectModel* model=[NSManagedObjectModel mergedModelFromBundles:nil]; 
     // If the persistent store is not compatible with such a model (i.e. it was created with a model obtained merging old versions of "submodels"), migrate 
     if(![model isConfiguration:nil compatibleWithStoreMetadata:storeMeta]){ 


      // Load the old model 
      NSManagedObjectModel*oldModel = [NSManagedObjectModel mergedModelFromBundles:nil forStoreMetadata:storeMeta]; 

      // Compute the mapping between old model and new model 
      NSMappingModel* mapping = [NSMappingModel inferredMappingModelForSourceModel:oldModel destinationModel:model error:&error]; 
      if(mapping){ 
       // Backup old store 
       NSURL* storeBackupURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:[NSString stringWithFormat:@"db.sqlite.%@.bck", [NSDate new]]]; 
       BOOL done = [[NSFileManager defaultManager] moveItemAtURL:storeURL toURL:storeBackupURL error:&error]; 
       if(done){ 
        // Apply the mapping 
        NSMigrationManager* migrationManager = [[NSMigrationManager alloc] initWithSourceModel:oldModel destinationModel:model]; 
        BOOL done = [migrationManager migrateStoreFromURL: storeBackupURL 
                   type: NSSQLiteStoreType 
                   options: nil 
                withMappingModel: mapping 
                toDestinationURL: storeURL 
                 destinationType: NSSQLiteStoreType 
                destinationOptions: nil 
                   error: &error]; 
        if(done){ 
         NSLog(@"Store migration successful!!!"); 
        } 
       } 
      } 
     } 
    } 
} 

if(error){ 
    NSLog(@"Migration error: %@", error); 
} 
+0

Tôi chỉ thấy mình viết khá nhiều mã này trước khi tôi đọc câu trả lời của bạn. Mặc dù xấu xí, điều này dường như là cách duy nhất để làm điều này. –

+0

Wow, cảm ơn, tôi đã bị mắc kẹt với vấn đề này trong nhiều giờ. Chỉ một câu hỏi, bạn có giữ tất cả các tệp sao lưu không? Tôi đoán một khi việc di chuyển được thực hiện thì không có hại gì khi xóa những số – Leonardo

+0

Wow điều này thực sự đã cứu được mông của tôi. Cảm ơn nhiều!! Vấn đề cụ thể của tôi là chúng tôi lấy một xcdatamodeld cũ để di chuyển thủ công từ một ứng dụng cũ và một phiên bản xcdatamodeld mới được phiên bản thích hợp. Tôi đoán Core Data đang nghẹn về điều này. –

Các vấn đề liên quan