CoreData 检查多对多关系是不是包含对象

Posted

技术标签:

【中文标题】CoreData 检查多对多关系是不是包含对象【英文标题】:CoreData check if to-many-relationship contains objectCoreData 检查多对多关系是否包含对象 【发布时间】:2013-05-28 09:47:48 【问题描述】:

我的应用中有以下数据模型:

基本上我想存储国家名称和城市名称。每个城市属于一个国家,一个国家包含 0 - n 个城市。

在我现在向某个国家/地区添加新城市之前,我需要知道该国家/地区是否已经包含具有此名称的城市。

直到现在我这样做:

- (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;

这显然很慢,我需要的是具有正确谓词的等效提取。我搜索一个这样的实体:

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];

但是,如果搜索涉及多个实体,我该怎么做?或者换句话说:如何仅为一个国家/地区添加唯一的城市名称?

【问题讨论】:

【参考方案1】:

如果你想检查一个给定的国家对象是否已经包含一个有名字的城市, 你可以做

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

或者,使用获取请求:

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

请注意,NSFetchedResultsController 通常用于显示 在表格视图中获取请求,因此这里不需要。

【讨论】:

嗨,马丁,感谢您的回复。这个解决方案看起来对我的代码只有很小的改进。有没有办法创建一个 fetchrequest 然后执行 countForFetchRequest: 为“国家不包含这个城市”返回 0 或为“国家包含这个城市”返回一个 > 0 的值?我真的不喜欢创建对象以减少内存使用... 我刚刚测试了你的代码,现在可以完美运行了。我编辑了您的答案代码,以便其他人可以利用它,非常感谢:) @pmk:不客气(是的,代码中有一些愚蠢的错误)。 - 我刚刚重新插入了便捷方法fetchRequestWithEntityName(现在希望是正确的),它节省了 2 行代码。 假设您有一个数组 cityNames ['CityA', 'CityB', 'CityC']。您将如何获取包含数组中所有城市或其中一个城市的国家/地区?

以上是关于CoreData 检查多对多关系是不是包含对象的主要内容,如果未能解决你的问题,请参考以下文章

CoreData :NSFetchedResultsController 一对多对多的关系

Swift、CoreData 和多对多关系:如何访问子项的顺序?

在 Swift 中将 NSManagedObject 添加到 CoreData 多对多关系时防止循环

CoreData 多对多关系

CoreData 多对多关系插入和删除操作

保存循环删除多对多CoreData关系的一端