tags:

views:

14

answers:

2

I've got a Core Data entity called "Card" which has a relationship "info" to another entity, "CardInfo". It's a one-to-many relationship: each card can have multiple CardInfos, but each CardInfo only has one Card.

The CardInfo entity just has two strings, "cardKey" and "cardValue". The object is to allow for arbitrary input of data for cards. Say, you wanted to know what color a card was. Then you added a CardInfo to each Card that had a cardKey of "color" and a cardValue of "black" or "red".

My general question is: what's the best way to get the set of Cards where each Card has a CardInfo where the CardKey and CardValue has specific values. For example: all Cards with relationship to CardInfo cardKey='color' and cardValue='red'? Ideally, I return an NSSet of all the appropriate Card * objects.

A: 

This is the answer that I came up with, but the two-part process seems inefficient to me. I figure there must be a more elegant way to do this with key-values or something

-(NSSet *)cardsWithCardKey:(NSString *)thisKey cardValue:(NSString *)thisValue {

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"CardInfo" 
        inManagedObjectContext:self.managedObjectContext];

    [fetchRequest setEntity:entity];

    NSPredicate *predicate = [NSPredicate
                              predicateWithFormat:@"(cardKey=%@) AND (cardValue=%@)",
                              thisKey,thisValue];

    [fetchRequest setPredicate:predicate];

    NSError *error;
    NSArray *items = [self.managedObjectContext 
        executeFetchRequest:fetchRequest error:&error];
    [fetchRequest release];

    NSMutableSet *cardSet = [NSMutableSet setWithCapacity:[items count]];
    for (int i = 0 ; i < [items count] ; i++) {
        if ([[items objectAtIndex:i] card] != nil) {
            [cardSet addObject:[[items objectAtIndex:i] card]];
        }
    }
    return [NSSet setWithSet:cardSet];
}
Shannon A.
+2  A: 

The loop at the end is not needed. A simple KVC call will clean it up nicely.

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:@"CardInfo" inManagedObjectContext:self.managedObjectContext]];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"cardKey = %@ AND cardValue = %@", thisKey, thisValue]];

NSError *error = nil;
NSArray *items = [[self managedObjectContext executeFetchRequest:fetchRequest error:&error];
[fetchRequest release], fetchRequest = nil;
NSAssert1(error == nil, @"Error fetching objects: %@\n%@", [error localizedDescription], [error userInfo]);

return [items valueForKeyPath:@"@distinctUnionOfObjects.card"];
Marcus S. Zarra
To back a set actually required:return [NSSet setWithArray:[items valueForKeyPath:@"@distinctUnionOfObjects.card"]];Thanks!
Shannon A.