0

I have three DataModels defined in my Application. My question is, if i need three different contexts? so three different sqlite files?

At the moment every time i save a record into my database i do the following:

managedObjectContext = [[AppDelegate sharedAppDelegate] getManagedObjectContextWithDB:@"TestDB.sqlite"];

Or if i save a record into my other DataModel i do:

managedObjectContext = [[AppDelegate sharedAppDelegate] getManagedObjectContextWithDB:@"TestDB2.sqlite"];

So is that the right way? Or do i have to have only one context for all three models?

Here are the other methods:

- (NSManagedObjectContext *)getManagedObjectContextWithDB:(NSString *)db
{
if (_managedObjectContext != nil) {
    return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinatorWithDB:db];
if (coordinator != nil) {
    _managedObjectContext = [[NSManagedObjectContext alloc] init];
    [_managedObjectContext setPersistentStoreCoordinator: coordinator];
}

return _managedObjectContext;
}

- (NSManagedObjectModel *)managedObjectModel {
if (_managedObjectModel != nil) {
    return _managedObjectModel;
}
_managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];

return _managedObjectModel;
}

- (NSPersistentStoreCoordinator *)persistentStoreCoordinatorWithDB:(NSString *)db {
if (_persistentStoreCoordinator != nil) {
    return _persistentStoreCoordinator;
}
NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory]
                                           stringByAppendingPathComponent: db]];

NSDictionary *options = @{
                          NSMigratePersistentStoresAutomaticallyOption : @YES,
                          NSInferMappingModelAutomaticallyOption : @YES
                          };
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc]
                               initWithManagedObjectModel:[self managedObjectModel]];
if(![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
                                              configuration:nil URL:storeUrl options:options error:&error]) {
    /*Error for store creation should be handled in here*/
}

return _persistentStoreCoordinator;
}
davidOhara
  • 1,008
  • 5
  • 17
  • 39

1 Answers1

1

If by data model you mean the model file containing entities and their relationships(file extension .xcdatamodel) then I believe the answer is yes. To interact with a data model you set up a persistent store coordinator and instantiate it with the model (as you have done). To interact with the managed objects you create a managed object context (which you have also done). Since this is not possible I am going to assume you only have one model file and instead have 3 seperate stores derived from this model.

Since you are interested in establishing several stores corresponding to the same model, an example would be if you have a default data store that comes pre-populated and then a user populated store, this is totally possible. All you need to do is call the addPersistentStoreWithType:configuration: again on your coordinator. There are plenty of SO posts on this so I won't go to in depth.

The one thing you do need to consider is that setting up several stores does mean that you need to watch your performance very carefully (you are on a mobile device after all). That being said you don't need to manage three different contexts, you only need to ensure that the stores are added to the same persistent store coordinator that your context communicates with. The coordinator will do all the work to figure out which store to read and write to.

I hope this helps!


EDIT

Following the comments it came to light that the original problem does indeed revolve around maintaining separate managed object model files and thus separate persistent store coordinators. The OP was actually having issues regarding the updates and inserts of these entities across the contexts. We then realized that the problem might be the fact that MO's were being accessed outside of their contexts and so the solution to that problem involves wrapping all updates to the MO in the [NSManagedObjectContext performBlock:] method. This gives us a thread safe means of accessing MO's.

A word of caution, setting up three separate models is a fairly complex solution and might not actually be necessary in most scenarios. Having separate models means that there is no way to have any relationships to entities in other models. My suggestion for beginners would be to use one model file and if it really is important to have separate stores you can always use the [NSManagedObjectModel mergedModelFromBundles:] method to create separate stores whilst still talking to the same coordinator. At the end of the day, one of the most powerful features of Core Data is its relationship management and setting up separate models limits that in many ways.

Community
  • 1
  • 1
Daniel Galasko
  • 23,617
  • 8
  • 77
  • 97
  • Hi, thx for the informations...But at the moment i have three *.xcdatamodel files. My only question is, if i need also three *.sqlite files? – davidOhara Jun 20 '14 at 07:27
  • Assuming you want to persist the contents to disk then yes, the only time you don't need a backing store is if you use the NSInMemoryStoreType option. For the model files you will need three persistent store coordinators and thus three contexts and three store files, hope this helps. – Daniel Galasko Jun 20 '14 at 07:29
  • It looks correct, what is happening in your application? – Daniel Galasko Jun 20 '14 at 07:33
  • Try this - when saving an MO, print out its context (mo.managedObjectContext) and then print out the context you are saving with, if these two are identical then please tell me what error you are getting? – Daniel Galasko Jun 20 '14 at 07:40
  • Hi, i will try it...But Problem is that i can´t say when the error occurs...i can´t reproduce it... – davidOhara Jun 20 '14 at 07:41
  • one reason might be if you are saving on a different thread. All your MO updates and saves must be in a [context performBlock:^{//do updates and saves here}]; Thats the only thing i can think of? – Daniel Galasko Jun 20 '14 at 07:44
  • Hmm, i don´t do this atm...So i could get the main Thread before saving with GDC?! – davidOhara Jun 20 '14 at 07:50
  • I wouldn't think of it in terms of GDC, the idea is that a context defines a thread safe mechanism for dealing with managed objects. This means that you should never access a MO outside of its context. The law is defined as "Thou shalt not cross the streams". So whenever you update a MO always do so in the performBlock: method to be safe. Alternatively you could always fetch properties as a dictionary in which case you don't need to use performBlock but thats for reads – Daniel Galasko Jun 20 '14 at 07:53
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/55958/discussion-between-chrizstone-and-daniel-galasko). – davidOhara Jun 20 '14 at 08:00