【问题标题】:Many To Many NSPredicate With NSFetchedResultsController多对多 NSPredicate 与 NSFetchedResultsController
【发布时间】:2014-12-03 19:39:51
【问题描述】:

我无法根据我的数据模型配置创建 NSPredicate 对象。

我有 2 个实体,一个叫 Bob,一个叫 Fred。 Bob 与 Fred 有一个称为“hasFreds”(反面是 hasBobs)的多对多关系,并且 Fred 有一个 BOOL 类型的属性 hasEaten。

我想获取 Bob 的列表,其中每个 Bob 至少有一个 Fred,hasEaten=YES。如果 hasEaten=YES 没有 Fred,我想返回所有没有 Fred 的 Bob。

这是我到目前为止所拥有的,但它并不完全有效(它不符合“如果没有带有 hasEaten=YES 的 Fred,我想返回所有没有 Fred 的 Bob”条件):

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

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

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

    fr.predicate = predicate1;


    NSFetchedResultsController *fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fr managedObjectContext:[[self appDelegate] managedObjectContext] sectionNameKeyPath:nil cacheName:nil];
    fetchedResultsController.delegate = self;

【问题讨论】:

    标签: core-data many-to-many nspredicate nsfetchedresultscontroller


    【解决方案1】:

    我认为从概念的角度来看,您的条件并不是真正的 one 查询。您想要进行两个查询,一个基于另一个的结果。这并不是 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 的解决方案也是可行的。

    【讨论】:

    • 我使用您的解决方案提出了类似的解决方案。在 controllerDidChangeContent 中,我正在检查是否需要使用 countForFetchRequest 切换谓词,然后根据需要进行更改。我通过告诉 NSFetchedResultsController 执行获取并重新开始来跟进更改。我会标记你的答案,因为它确实对我有很大帮助
    • 嗯,它本质上是相同的解决方案,所以你应该接受这个答案。只是 FRC 的交付机制略有不同 - 并不是解决方案的关键点。
    【解决方案2】:

    感谢用户 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];
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-09
      • 1970-01-01
      相关资源
      最近更新 更多