views:

1092

answers:

3

Hi,

I have been reading through the core data documentation and feel I am still missing something.

I do not quite understand how you insert objects into a relationship of another object.

For example the following two Entities are in my model

flightDepartureBoard name: from_airport: to_airport: current_flights: (this is a one to many relationship of flight detail entities)

flight_details arrive depart name

So my data contains a list of different departure boards for a few airports. Each departure board then contains a number of flight_details containing info on the current arrivals and departures for that airport.

My current understanding is to insert the flight details for a specific departure board, I must get the managedObject for the board, then create a new managed object for each flight and set its values as appropriate then create an NSSet conatining the flight managed objects and set the depatureboards managedObject current_flights (the relationship) to the just created NSSet. Is this correct?

What if I want to add new entries? I assume I do not need to fetch the entire set first?

Thanks for any help..

A: 

Although I just realised I could set the relationship to the current object on the flightDetails object instead..

J T
+1  A: 

When you define the relationship in the data model the set is defined in the header of the containing object. Just add or remove items from the set using the normal NSMutableSet methods.

To add a new managed entity you will do something like:

Task* newTask = [NSEntityDescription insertNewObjectForEntityForName:@"Task" inManagedObjectContext:self.managedObjectContext];

If you grab the Location sample from Apple and work from there you will puzzle it out although that contains no relationships. To get it all working just change your data model to what it needs to be and don't think of it as a relationship, just think of it as "A has a NSMutableSet of B". Because you defined the reverse relationship as the documentation recommended you don't need to think about what B has of A, just start thinking in terms of B when that's the object that matters to you.

Let's say you have an Airport object which has a Board object (and imagining you set origin and destination into Flight with a variable routingArray, then just create your Flight objects as necessary and set the relationship like:

Flight* newFlight = [NSEntityDescription insertNewObjectForEntityForName:@"Flight" inManagedObjectContext:self.managedObjectContext];
[newFlight setRoute:routingArray];
[Airport.Board.flights addObject:newFlight];

When the flight is cancelled (curse you, United!) you can just remove the Flight from that set and anyone who tries to access the object where it used to be see nil, so you can cheerfully ruin the passengers day.

Adam Eberbach
Fantastic thanks this is pretty much exactly what I was wondering. I managed to get the task done with something similar but upon reflection I was still not quite spot on.
J T
I forgot to say- the first thing that happens after you change the data model is that everything crashes - either you change the name of the storage file in the Core Data init functions (not the right way) or you add a version to the data model (the right way) - just go a little further in the big CD docs and you will find adding a model version is really easy. If you're happy with the answer an accept is always appreciated.
Adam Eberbach
+2  A: 

There are a few options:
1. You can use add<Key>Object: on a NSManagedObject:

NSManagedObject *flightBoard = [NSEntityDescription insertNewObjectForEntityForName:@"FlightDepartureBoard" inManagedObjectContext:self.managedObjectContext];
NSManagedObject *details = [NSEntityDescription insertNewObjectForEntityForName:@"Flight_Details" inManagedObjectContext:self.managedObjectContext];
[flightBoard addCurrent_flightsObject:details];

Although you will get a compiler warning unless you define the accessors in a category:

@interface NSManagedObject (Current_flightsAccessors)
- (void)addCurrent_flightsObject:(NSManagedObject *)value;
- (void)removeCurrent_flightsObject:(NSManagedObject *)value;
- (void)addCurrent_flights:(NSSet *)value;
- (void)removeCurrent_flights:(NSSet *)value;
@end

2. Subclass. You can generate class files from your model which will include accessors for the to-many relationships:

FlightDepartureBoard.h:

#import <CoreData/CoreData.h>
@class Flight_Details;
@interface FlightDepartureBoard : NSManagedObject 
{
}
@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSString * from_airport;
@property (nonatomic, retain) NSString * to_airport;

@interface FlightDepartureBoard (CoreDataGeneratedAccessors)
- (void)addCurrent_flightsObject:(Flight_Details *)value;
- (void)removeCurrent_flightsObject:(Flight_Details *)value;
- (void)addCurrent_flights:(NSSet *)value;
- (void)removeCurrent_flights:(NSSet *)value;
@end

FlightDepartureBoard.m:

#import "FlightDepartureBoard.h"
#import "Flight_Details.h"
@implementation FlightDepartureBoard
@dynamic name;
@dynamic from_airport;
@dynamic to_airport;
@dynamic current_flights;
@end

3. You can get the mutable set and modify it using mutableSetValueForKey:. For example:

NSManagedObject *flightBoard = [NSEntityDescription insertNewObjectForEntityForName:@"FlightDepartureBoard" inManagedObjectContext:self.managedObjectContext];
NSManagedObject *details = [NSEntityDescription insertNewObjectForEntityForName:@"Flight_Details" inManagedObjectContext:self.managedObjectContext];
NSMutableSet *flights = [flightBoard mutableSetValueForKey:@"current_flights"];
[flights addObject:details];

For more information, check out Managed Object Accessor Methods.

gerry3
Excellent thanks I understand it now. I just could not quite see the solution from the documents.
J T
If you found this answer or Adam's useful, please accept one of them.
gerry3
Sorry still new to this site. Both answers were equally helpful in reality. Thanks for the help, much appreciated.
J T
In lieu of an accept, an up vote is always a nice gesture.
gerry3