Core data 使用NSFetchedResultsController进行多对多NSPredicate

Core data 使用NSFetchedResultsController进行多对多NSPredicate,core-data,many-to-many,nspredicate,nsfetchedresultscontroller,Core Data,Many To Many,Nspredicate,Nsfetchedresultscontroller,根据数据模型配置创建NSPredicate对象时遇到问题 我有两个实体,一个叫鲍勃,一个叫弗雷德。Bob与Fred有一种称为“hasFreds”(反面是hasBobs)的多对多关系,Fred有一个类型为BOOL的HasEat属性 我想取一份Bob的名单,每个Bob至少有一个Fred,haseat=YES。如果没有带有haseat=YES的FRED,我想返回所有没有FRED的BOB 这就是我到目前为止所拥有的,它不太有效(它不符合“如果没有带haseat的Fred=是,我想返回所有不带Fred的B

根据数据模型配置创建NSPredicate对象时遇到问题

我有两个实体,一个叫鲍勃,一个叫弗雷德。Bob与Fred有一种称为“hasFreds”(反面是hasBobs)的多对多关系,Fred有一个类型为BOOL的HasEat属性

我想取一份Bob的名单,每个Bob至少有一个Fred,haseat=YES。如果没有带有haseat=YES的FRED,我想返回所有没有FRED的BOB

这就是我到目前为止所拥有的,它不太有效(它不符合“如果没有带haseat的Fred=是,我想返回所有不带Fred的BOB”条件):


我认为从概念的角度来看,你的条件并不是一个真正的问题。您需要进行两个查询,一个基于另一个查询的结果。这并不是SQL查询的真正目的,更不用说对象图谓词了

因此,我认为最简单、最直观的解决方案应该是使用两个版本的“获取结果”控制器

您可以通过动态更改谓词来创建另一个版本。(我经常使用这种模式,例如用于搜索。)因为子查询无论如何都会导致多次访问持久存储,所以在为获取的结果控制器设置谓词之前,您可以只进行一次有效的获取以评估条件

设置谓词后,如有必要,请将其删除:

if ([context countForFetchRequest:request] == 0) { 
   request.predicate = nil; 
}
// continue creating your FRC with the request
请注意,
countForFetchRequest
非常高效,不占用内存

要更新

self.fetchedResultsController = nil;
[self.tableView reloadData]; // or collection view

如果您需要利用FRC的缓存功能,那么按照上述模式使用两个独立FRC的解决方案也是可行的。

多亏了用户Mundi,我才能够想出一个解决方案。首先是实现一个名为getCorrectPredicate的方法

-(NSPredicate *)getCorrectPredicate{

        NSPredicate *predicate1;
        NSFetchRequest *fr;

        predicate1 = [NSPredicate predicateWithFormat:
                      @"(SUBQUERY(hasFreds, $fred, $fred.hasEaten = %@).@count > 0)",@YES];

        fr = [NSFetchRequest fetchRequestWithEntityName:@"Bob"];

        fr.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"date" ascending:NO selector:@selector(compare:)]];

        fr.predicate = predicate1;

        if([[[self appDelegate] managedObjectContext] countForFetchRequest:fr error:nil] == 0){
            // we have a none situation
            self.predicateState = [NSPredicate predicateWithFormat:
                                   @"hasFreds.@count=0"];
        }else{
            self.predicateState = predicate1;
        }
        return self.predicateState;
    }
第二个是检查NSFetchedResultsController委托方法controllerDidChangeContent中的谓词是否更改

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller{

        [_expensesTable endUpdates];

        [[[self frc] fetchRequest] setPredicate:[self getCorrectPredicate]];
        [self performFetch];
    }

我用你的解决方案想出了一个类似的解决方案。在controllerDidChangeContent中,我使用countForFetchRequest检查是否需要切换谓词,然后根据需要进行更改。我通过告诉NSFetchedResultsController执行蚀刻并重新开始来跟踪更改。我会记下你的答案,因为它确实帮了我很多忙。嗯,基本上是相同的解决方案,所以你应该接受这个答案。只是FRC的交付机制略有不同——这并不是解决方案的关键点。
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller{

        [_expensesTable endUpdates];

        [[[self frc] fetchRequest] setPredicate:[self getCorrectPredicate]];
        [self performFetch];
    }