Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CoreData check if to-many-relationship contains object

I have the following data model in my app:

data model

Basically I want to store country names aswell as city names. Each city belongs to one country and one country contains 0 - n cities.

Before I now add new cities to a certain country I need to know if the country already contains a city with this name.

Until now I do this:

- (BOOL)countryForName:(NSString *)countryName containsCity:(NSString *)cityName {
    Countries *country = [self countryForName:countryName];
    NSSet *cityNames = [country valueForKey:@"cities"];
    for (Cities *city in cityNames) {
        if ([city.cityName isEqualToString:cityName]) {
            return YES;
        }
    }
    return NO;
}

This obviously is very slow, what I need is an equivalent fetch with a correct predicate. I perform a search for one entity like this:

NSEntityDescription *entity     = [NSEntityDescription entityForName:@"Countries" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];

// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor    = [[NSSortDescriptor alloc] initWithKey:@"countryName" ascending:YES];
NSArray *sortDescriptors            = @[sortDescriptor];
fetchRequest.sortDescriptors        = sortDescriptors;

// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:@"GetCountryList"];
aFetchedResultsController.delegate  = self;
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"countryName == %@", countryName];
[aFetchedResultsController.fetchRequest setPredicate:predicate];

But how do I do this if a search involves multiple entities? Or in other words: How do I add unique city names for one country only?

like image 242
pmk Avatar asked May 28 '13 09:05

pmk


1 Answers

If you want to check that a given country object already contains a city with a name, you can do

Countries *country = ...
NSString *cityName = ...
if ([[country valueForKeyPath:@"cities.name"] containsObject:cityName]) {
    // ...
}

Or, using a fetch request:

NSString *countryName = ...
NSString *cityName = ...
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Countries"];

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"countryName == %@ AND ANY cities.cityName == %@", countryName, cityName];
[fetchRequest setPredicate:predicate];

NSError *error;
NSUInteger count = [self.managedObjectContext countForFetchRequest:fetchRequest error:&error];

if (count == NSNotFound) {
    // error
} else if (count == 0) {
    // no matching country
} else {
    // at least one matching country
}

Note that a NSFetchedResultsController is normally used to display the contents of a fetch request in a table view, so it is not needed here.

like image 199
Martin R Avatar answered Sep 23 '22 01:09

Martin R