2012-04-19 29 views
11

Tôi có một dự án iOS với một cơ sở dữ liệu lớn, được tải sẵn và một cơ sở dữ liệu người dùng nhỏ (cả hai cửa hàng SQLite CoreData). Các câu hỏi trước đã đề xuất sử dụng các cấu hình để kiểm soát những Thực thể nào được sử dụng với cửa hàng nào. Tôi gặp khó khăn khi làm việc đó. Đây là những gì tôi đã cố gắng ...CoreData với nhiều cửa hàng: cấu hình tai họa

- (NSManagedObjectModel *)managedObjectModel 
{ 
    if (_managedObjectModel != nil) return _managedObjectModel; 
    // set up the model for the preloaded data 
    NSURL *itemURL = [[NSBundle mainBundle] URLForResource:@"FlagDB" withExtension:@"momd"]; 
    NSManagedObjectModel *itemModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:itemURL]; 
    // set up the model for the user data 
    NSURL *userDataURL = [[NSBundle mainBundle] URLForResource:@"UserData" withExtension:@"momd"]; 
    NSManagedObjectModel *userDataModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:userDataURL]; 
    // merge the models 
    _managedObjectModel = [NSManagedObjectModel modelByMergingModels:[NSArray arrayWithObjects:itemModel, userDataModel, nil]]; 
    // define configurations based on what was in each model 
WRONG [_managedObjectModel setEntities:itemModel.entities forConfiguration:@"ItemData"]; 
WRONG [_managedObjectModel setEntities:userDataModel.entities forConfiguration:@"UserData"]; 
    return _managedObjectModel; 
} 

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator 
{ 
    if (_persistentStoreCoordinator != nil) return _persistentStoreCoordinator; 
    // preloaded data is inside the bundle 
    NSURL *itemURL = [[[NSBundle mainBundle] bundleURL] URLByAppendingPathComponent:@"FlagDB.sqlite"]; 
    // user data is in the application directory 
    NSURL *userDataURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"UserData.sqlite"]; 

    NSManagedObjectModel *mom = self.managedObjectModel; 
    NSError *error = nil; 
    NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom]; 

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

Hủy bỏ này với "Mô hình được sử dụng để mở cửa hàng không tương thích với cửa hàng được sử dụng để tạo cửa hàng". Kiểm tra các hash trong mô hình đối với các hash trong kho lưu trữ rằng chúng giống hệt nhau đối với các thực thể có trong cấu hình ItemData.

Nếu tôi cố gắng làm một sự chuyển đổi trọng lượng nhẹ, như vậy:

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil]; 

    NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom]; 
    if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:@"ItemData" URL:itemURL options:options error:&error]) 

Nó không thành công với 'NSInvalidArgumentException', lý do: ' '' mẫu không chứa cấu hình' ItemData Tôi cho rằng đó là vì một mô hình mới đang được tạo ra bởi quá trình di chuyển nhẹ và nó không chứa cấu hình của tôi.

Dựa trên một số đề xuất trong các chủ đề khác, tôi đã thử thực hiện di chuyển nhẹ mà không cần cấu hình và sau đó tạo điều phối viên mới bằng cấu hình. Loại công việc này, nhưng nó thêm các bảng vào tệp .sqlite được tải sẵn của tôi tương ứng với các thực thể dữ liệu người dùng (không thuộc về đó) và tạo cả các bảng dữ liệu được tải sẵn và các bảng dữ liệu người dùng trong kho dữ liệu người dùng mới được tạo ra. . Kết quả cuối cùng là tìm nạp thất bại, dường như bởi vì họ đang tìm kiếm trong cửa hàng sai.

NSDictionary *migrationOptions = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil]; 

// make a temp persistent store coordinator to handle the migration 
NSPersistentStoreCoordinator *tempPsc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom]; 
// migrate the stores 
if (![tempPsc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:itemURL options:migrationOptions error:&error]) 
{ 
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
    abort(); 
} 
if (![tempPsc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:userDataURL options:migrationOptions error:&error]) 
{ 
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
    abort(); 
} 

// make a permanent store coordinator 
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom]; 

NSDictionary *readOnlyOptions = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSReadOnlyPersistentStoreOption, nil]; 
if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:@"ItemData" URL:itemURL options:readOnlyOptions error:&error]) 
{ 
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
    abort(); 
} 

/*if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:@"UserData" URL:userDataURL options:nil error:&error]) 
{ 
NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
abort(); 
}*/ 

Và sau đó ...

OSAppDelegate *delegate = [UIApplication sharedApplication].delegate; 
    NSManagedObjectContext *context = delegate.managedObjectContext; 
    // sanity check 
    for (NSPersistentStore *store in context.persistentStoreCoordinator.persistentStores) { 
     NSLog(@"store %@ -> %@", store.configurationName, store.URL); 
     NSMutableArray *entityNames = [[NSMutableArray alloc] init]; 
     for (NSEntityDescription *entity in [context.persistentStoreCoordinator.managedObjectModel entitiesForConfiguration:store.configurationName]) { 
      [entityNames addObject:entity.name]; 
     } 
     NSLog(@"entities: %@", entityNames); 
    } 

    NSFetchRequest *categoryFetchRequest = [[NSFetchRequest alloc] init]; 
    categoryFetchRequest.entity = [NSEntityDescription entityForName:@"Category" inManagedObjectContext:context]; 
    categoryFetchRequest.predicate = [NSPredicate predicateWithFormat:@"name == %@", categoryName]; 
    NSError *error = nil; 
    Category *category = [[delegate.managedObjectContext executeFetchRequest:categoryFetchRequest error:&error] lastObject]; 

này hoạt động tốt, trở về đối tượng loại tên một cách thích hợp, cho đến khi tôi bỏ ghi chú việc bổ sung các cửa hàng thứ hai. Nếu tôi làm điều đó, kết quả tìm nạp sẽ trở lại trống. Các thông điệp NSLog chẩn đoán in chính xác những gì tôi mong đợi. Mỗi cửa hàng được liên kết với cấu hình chính xác và mỗi cấu hình có các thực thể thích hợp.

Có ai có thể chỉ cho tôi mã nguồn để thiết lập nhiều cửa hàng đang hoạt động hay không hay biết tôi đang làm gì sai? Cảm ơn trước!


SOLVED: Điểm mấu chốt của vấn đề là hai dòng đánh dấu sai trong các mã đầu tiên trong danh sách. Tôi đã cố tạo cấu hình theo lập trình, nhưng điều đó dường như không đủ. Nếu bạn truy vấn ManagedObjectModel cho các cấu hình sau khi thực hiện việc này, bạn làm thực sự thấy các cấu hình trong danh sách và các thực thể đúng được liên kết với các cấu hình đó. Tuy nhiên, có vẻ như một cái gì đó khác cần phải được thực hiện để làm cho PersistentStoreCoordinator có thể sử dụng đúng cách. Tạo cấu hình trong Xcode làm cho chúng hoạt động.


THEO D 01I: Có thêm một dấu phụ. Các giải pháp chạy một di chuyển riêng biệt vượt qua trước khi thiết lập cuối cùng Persistent Store Điều phối viên hoạt động tuyệt vời ... trong giả lập. Trên một thiết bị thực tế, các điều khoản sẽ nghiêm ngặt hơn. Nếu bạn cố gắng thực hiện di chuyển đó, nó không thành công vì cửa hàng trong gói Ứng dụng là chỉ đọc. Việc di chuyển có vẻ là cần thiết trừ khi bạn hợp nhất các mô hình của mình. Nếu bạn chỉ có một mô hình và cửa hàng trong gói Ứng dụng tương thích với nó, việc di chuyển là không cần thiết và truy cập bằng cách sử dụng cấu hình được xác định trong Xcode hoạt động.

Tùy chọn khác có thể là di chuyển dữ liệu vào thư mục Tài liệu trước khi thử di chuyển. Tôi chưa xác minh rằng cách tiếp cận đó hoạt động.

+0

Đảm bảo bạn đang thực hiện di chuyển trên thư mục tài liệu người dùng của hộp cát ứng dụng - đó là đọc/ghi - chứ không phải trong chính gói ứng dụng. – Sunny

+0

Tôi không muốn di chuyển dữ liệu vào thư mục Tài liệu vì tôi không muốn dữ liệu (tĩnh) đó được sao lưu và được tính vào hạn ngạch iCloud của người dùng. Nhưng có vẻ như trong iOS 5.0.1 có một cách để chỉ định các tệp không được sao lưu: http://developer.apple.com/library/ios/#qa/qa1719/_index.html – Aneel

+2

Vâng, bạn đã truyền cảm hứng cho tôi và sau khi dành một vài giờ để giải quyết vấn đề của tôi, tôi đã viết một bài báo đầy đủ về điều này [ở đây] (http://blog.atwam.com/blog/2012/05/11/multiple-persistent-stores-and-seed-data -with-core-data /). Tôi nghĩ rằng nó có thể giúp một số người khác trong tương lai. – Wam

Trả lời

5

Bạn đã thử cả hai cấu hình được xác định trong cùng một mô hình (ví dụ: cùng một momd)? Bạn có thể làm điều này một cách dễ dàng bằng cách chọn "Editor-> Add Configuration" trong khi chỉnh sửa một trong các mô hình dữ liệu của bạn. Kéo các thực thể cho UserData và ItemData vào cấu hình thích hợp. Cấu hình được chỉ định theo cách này là những gì mà Core Data tôn trọng; nó không phải về tên tệp/URL. Khi bạn đã thực hiện xong ở trên, sau đó đơn giản hóa _managedObjectModel của bạn ở trên để tìm kiếm tệp momd/URL đơn lẻ bất cứ khi nào nó được gọi. Ngoài ra, nếu bạn quyết định giữ hai tệp momd riêng biệt, hãy đảm bảo bạn đã xác định các mô hình của mình trong Cấu hình có tên "UserData" và "ItemData" tương ứng trong tệp định nghĩa mô hình của chúng.

Đề xuất ban đầu của tôi là giữ một tệp mô hình. Trừ khi có một lý do các cấu hình này không thể nằm trong cùng một mô hình đối tượng, nó không có ý nghĩa làm phức tạp mọi thứ với nhiều tệp. Tôi nghĩ rằng sẽ rất khó để phát triển Core Data để làm những gì bạn mang đến để làm ở trên. Cố gắng đơn giản hóa phần mô hình hóa mã của bạn.

+1

Cảm ơn bạn đã trả lời. Tôi có một lý do tốt để sử dụng hai mô hình riêng biệt. Mô hình Dữ liệu mặt hàng được chia sẻ với một dự án khác (ứng dụng OS X được sử dụng để tạo/chỉnh sửa tập dữ liệu). Nếu có thể, tôi muốn có thể giữ riêng hai mô hình. – Aneel

+1

Tôi đã thử những gì bạn đề xuất và nó hoạt động. Tôi đã sao chép mô hình dữ liệu người dùng vào mô hình dữ liệu mặt hàng và tạo hai cấu hình trong XCode. Tôi phải tạo một PSC tạm thời và thực hiện di chuyển nhẹ mà không có cấu hình trên mỗi kho dữ liệu, sau đó tạo một PSC khác và thêm mỗi cửa hàng với cấu hình thích hợp. Không có những bước đó, tôi vẫn gặp lỗi. Với họ, PSC kết hợp từng thực thể với đúng cửa hàng. Tôi nghĩ rằng mô hình thống nhất kém hiệu quả hơn so với giải pháp khác của tôi là có hai MOM/PSC/MOC riêng biệt. Cảm ơn! Tôi vẫn muốn một cách để làm điều này với hai mô hình riêng biệt. – Aneel

+1

Được rồi, tôi cũng đã thử những gì bạn đề xuất để giữ riêng các mô hình. Điều đó cũng hoạt động! Có vẻ như cốt lõi của vấn đề của tôi là việc xác định các cấu hình trong lập trình với ManagedObjectModel addEntities: forConfiguration: không hoạt động. Chúng hiển thị khi bạn truy vấn MOM cho các cấu hình của nó, nhưng chúng thực sự dường như không được PSC sử dụng đúng cách. Tạo cấu hình trong Xcode phải làm nhiều hơn sau hậu trường. – Aneel

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