简体   繁体   中英

How do I add an NSManagedObject to Core Data and specify it's “parent” object? (iPhone)

Okay, here's the situation. I have two NSManagedObjects called Store and Aisle . There is a one-to-many relationship from Store to Aisle and a one-to-one relationship from Aisle to Store .

I have existing stores added in Core Data that I can access just fine. My problem is that I cannot figure out how to add an Aisle object to an existing Store . I've tried fetching the Store and then adding an Aisle object to the .Aisles set, I've tried using the AddAislesObject: method provided by CoreData in Store.h , and I've tried adding a Store object to the .Stores set in the Aisle object.

I'm watching my SQLite database and it looks like the Aisles are being added successfully and that they are associated to the correct Store using the Core Data primary key. But for some reason when I try to retrieve the Aisle objects (using the .Aisles property of the fetched Store object) I always get a zero-count NSSet .

I've also tried deleting my .sqlite file to no avail.

Does anyone have some simple code or even a high level suggestion for the best way to do this?

Thank you!

--- UPDATE 8/30 0917 CST

I've taken some of Adam's suggestions below and my aisles are definitely saving into Core Data correctly. However, when I try to access the saved Aisle from the Store object, I'm not getting anything returned. In the code below you can see that I'm retrieving an existing Store object from Core Data using a name and location (there are safeguards on insert to make sure that this combination is unique). I then use some NSLog debugs to access the single Store in the returned array, and the aisles property to iterate through any aisles. Ignore everything below the debug loops because I haven't finished the method yet.

What I'm seeing is that aisleList has zero objects in it.

-(NSArray *)getAisleListByStore: (Store *)aStore {

// this method should return an NSArray of aisles for aStore

NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Store" inManagedObjectContext:context];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name MATCHES[c] %@ AND location MATCHES[c] %@", aStore.name, aStore.location];

[fetchRequest setEntity:entity];
[fetchRequest setPredicate:predicate];

NSError *error;
NSArray *storesList = [context executeFetchRequest:fetchRequest error:&error];
[fetchRequest release];

if (storesList == nil || [storesList count] != 1) {

    // error detected
    NSLog(@"Error retrieving stores: %@", [error localizedDescription]);
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Error retrieving stores" delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];
    [alert show];
    [alert release];
    return nil;

} else {

    // get aisles

    // debugs
    for (Store *theStore in storesList) {
        NSLog(@"Name: %@", theStore.name);
        NSLog(@"Aisle count: %d", [theStore.aisles count]);
        NSSet *aisleList = theStore.aisles;

        for (Aisle *theAisle in aisleList) {
            NSLog(@"Aisle name: %@", theAisle.name);
        }
    }

    // Store *theStore = [storesList objectAtIndex:0];

    // NSArray *aisles = (NSArray *)theStore.aisles;
    // return aisles;
}

}

No need for a third table.

You probably have a NSSet* in Store, but you have an Store* attribute in Aisle. This is one huge advantage of following Core Data's advice about making every relationship have an inverse.

Store* store = [NSEntityDescription insertNewObjectForEntityForName:@"Store" inManagedObjectContext:moc];
Aisle* aisle = [NSEntityDescription insertNewObjectForEntityForName:@"Aisle" inManagedObjectContext:moc];

Assuming the Aisle entity has the relationship inStore as an inverse of Store's to-many aisles relationship:

aisle.inStore = store;

You'll find Core Data takes care of the other side of the relationship, ie adding the Aisle to Store's NSSet.

Don't forget:

  NSError *error;
  if (![moc save:&error]) 
  {
    NSLog(@"Core Data Save error %@, %@", error, [error userInfo]);
  }

to make your changes permanent.

First off, is your relationship from Store to Aisle actually called Aisles or is it called aisles or aisle ? Make sure all your spelling is correct. Also, the relationship should be called aisles as it is a relationship, not an entity and it is to-many. You should also make sure that the to-one relationship from Aisle to Store (that should be called store ) is the inverse relationship of the to-many Store to Aisle relationship. Then if you grab a Store entity and use NSSet *aisleSet = storeEntity.aisles; you should get a correct set.

How about slipping a third table between these two tables to connect them? This pairs Stores with Aisles ids and provides the eitherway connections. Call it StoreAisle.

You have a store and want the aisles? Find the store you want in the store table, take that store ID, look in the StoreAisle table to find the IDs for the aisles from the Aisles table.

You have an aisle and want the store? Find the aisle that you want in the aisle table, take that ID and look in the StoreAisle table for the store ID that you then look in the Store table.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM