santibernaldo
santibernaldo

Reputation: 835

Fetch objects in Core Data through one to many relationship

I have this One-to-Many relationship in Core Data:

enter image description here

Each SBQChrono can have many SBQLaps.

In my model I have the class SBQLap:

@interface CILap : NSObject

@property (strong, nonatomic) NSDate * lapDate;

@end

And the class SBQChrono:

@interface CIChrono : NSObject

@property (strong, nonatomic) NSDate * startDate;
@property (strong, nonatomic) NSDate * stopDate;
@property (strong, nonatomic) NSOrderedSet *laps;

@end

I get all the SBQChrono entities doing:

NSFetchRequest *request=[[NSFetchRequest alloc] initWithEntityName:kChronoEntityName];

NSError *error;
NSArray *objects = [appContext.managedObjectContext executeFetchRequest:request error:&error];

How can I get the specified SBQLap entitys per each SBQChrono I find? Ive read a lot of posts and cant get the solution.

UPDATE:

After trying to cast the NSManagedObject, I realized that the laps is returned as nil value.

Doing:

for (NSManagedObject *oneObject in objects) {

    CIChrono *chrono=(CIChrono *)oneObject;

    NSLog(@"startDate %@", chrono.startDate);
    NSLog(@"stopDate %@", chrono.stopDate);
    NSLog(@"laps %@",chrono.laps);

} I get the message:

2014-01-28 14:39:48.379 Chrono[2341:70b] startDate 2014-01-28 12:27:53 +0000
2014-01-28 14:39:48.380 Chrono[2341:70b] stopDate 2014-01-28 12:27:54 +0000
2014-01-28 14:39:48.380 Chrono[2341:70b] -[NSManagedObject laps]: unrecognized selector sent to instance 0x8b959b0
2014-01-28 14:39:48.383 Chrono[2341:70b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSManagedObject laps]: unrecognized selector sent to instance 0x8b959b0'

Thanks

Upvotes: 1

Views: 3658

Answers (6)

Brian Webster
Brian Webster

Reputation: 12045

Looking at the model screenshot and code that you posted, it appears that the model has the relationship name set as lap (singular) but your class definition is using laps (plural). Core Data would be implementing an accessor for lap, but doesn't understand laps since it doesn't match the name in the model. Changing the model to say laps should fix that problem.

Upvotes: 0

Marcus S. Zarra
Marcus S. Zarra

Reputation: 46718

Lots of interesting answers on this one.

The answer is very simple and does not require subclassing NSManagedObject to access the objects in a relationship. You just need to use KVC (Key Value Coding) to access those objects. This is true of relationships and attributes.

If you want to use synthesized methods you can by subclassing as some have hinted at but that is not necessary.

Here is an extension to your example that you posted in your question:

for (NSManagedObject *oneObject in objects) {

    CIChrono *chrono=(CIChrono *)oneObject;

    NSLog(@"startDate %@", [chrono valueForKey:@"startDate");
    NSLog(@"stopDate %@", [chrono valueForKey:@"stopDate"]);
    NSLog(@"laps %@", [chrono valueForKey:@"laps"]);

    NSSet *laps = [chrono valueForKey:@"laps"];

    for (NSManagedObject *lap in laps) {
        NSLog(@"Lap entity: %@", lap);
    }
}

Note the -valueForKey: calls. Those are Key Value Coding which NSManagedObject instances (and all other Objective-C objects) respond to. I would suggest reading the documentation on KVC and KVO.

Upvotes: 6

markturnip
markturnip

Reputation: 402

You can fetch objects which have a relationship to 'SBQChrono'.

This can be done with two fetch requests, first fetch all the 'SBQChrono' objects & then perform a second request for 'SBQLap' entities with a predicate:

[NSPredicate predicateWithFormat:@"chrono IN %@",objects]

Upvotes: 0

bbarnhart
bbarnhart

Reputation: 6710

Each SQBChrono object contains a set of SBQLap objects that are associated with it. Look at your SQBChrono properties

@property (strong, nonatomic) NSOrderedSet *laps;

laps is a property that contains the many SBQLap objects to one SQBChrono object.

You can get an array from the set like this:

NSFetchRequest *request=[[NSFetchRequest alloc] initWithEntityName:kChronoEntityName];
NSError *error;
NSArray *chronoObjectArray = [appContext.managedObjectContext executeFetchRequest:request error:&error];

for (SQBChrono * chrono in chronoObjectArray) {
    NSArray *lapsArray = [chrono.laps array];
    NSLog("Chrono: %@   laps: %@", chrono.startDate, lapsArray);
}

Upvotes: 2

Florian Burel
Florian Burel

Reputation: 3456

Your array objects contains all your SBQChrono objects.

You can get all the SBQLaps associated with one chrono by doing:

SQBChrono * myChrono = objects[indexOfTheDesiredChrono];

The laps of the chrono are then in myChrono.laps, which is a NSOrderedSet (collection) of SBQLaps. Can be turn into an array like this :

NSArray * myChronoLaps = [myChrono.laps array]

Upvotes: 0

CW0007007
CW0007007

Reputation: 5681

As you've added the SBQChrono objects to an array you will need to cast it:

SQBChrono *anObject = (SQBChrono *)objects[0];

Then you can:

anObject.laps;

Will give you the NSSet of all associated objects ?

Upvotes: 0

Related Questions