如何在使用Core Data时正确设置NSPredicate以实现多对多关系?

时间:2009-08-28 15:34:27

标签: iphone core-data

我有一个Core Data模型,其中Task实体包含ExcludedDay实体的可选多对多关系ExcludedDays。 ExcludedDay的一个属性是day,它是一个NSDate对象。 ExcludedDay实体与Task实体具有反向强制关系。

为了获取指定日期的任务,我需要确保指定的日期不会显示为任何ExludedDay实体的day属性。

我开始尝试

NSPredicate *dayIsNotExcludedPredicate = [NSPredicate predicateWithFormat: @"ALL excludedDays.day != %@", today];

然而,尽管文档说明了,但ALL不起作用且应用程序抛出异常:由于未捕获的异常'NSInvalidArgumentException'而终止应用程序,原因:'不支持的谓词。

在此论坛中发布相同的问题之后,我能够在各种人的帮助下设计以下谓词:

NSPredicate * dayIsNotExcludedPredicate = [NSPredicate predicateWithFormat: @"excludedDays.@count == 0 || (excludedDays.@count > 0 && NONE excludedDays.day == %@))", today];

虽然这首先起作用,但我刚刚发现,只有当ExcludedDay实体仅包含一天时,这才有效。一旦ExcludedDay实体包含同一任务的一天以上,该谓词就会停止工作。因此,即使当天在ExcludedDay实体中显示为一天,也会选择一天的任务,这当然是错误的。问题与作为NSDate对象的属性日无关:用相应的NSString替换day或者用整数替换,我仍然面临同样的问题和不正确的行为。

在这种情况下实现谓词的正确方法是什么?在使用核心数据时,这可能是与任何聚合运算符相关的错误吗? 提前谢谢你,这让我发疯了。

2 个答案:

答案 0 :(得分:43)

事实证明,这是文档丢失和/或不一致的另一个问题。

在这种情况下,正确的谓词如下:

[NSPredicate predicateWithFormat:@"(excludedOccurrences.@count == 0) OR (0 == SUBQUERY(excludedOccurrences, $sub, $sub.day == %@).@count)", today]

在谓词中,子查询用于测试具有与您的测试日期匹配的日期的相关excludedOccurrences的数量是否等于零。但是,文档具有误导性。下面是Predicate Programming Guide关于谓词与多对多关系的结合使用的内容。

使用具有关系的谓词

如果使用to-many关系,则谓词的构造会略有不同。如果您想获取其中至少有一名员工的名字为“Matthew”的部门,您可以使用ANY运算符,如以下示例所示:

NSPredicate *predicate = [NSPredicate predicateWithFormat:
    @"ANY employees.firstName like 'Matthew'"];

如果您想找到所有员工的薪酬超过一定金额的部门,您可以使用ALL运算符,如下例所示:

float salary = ... ;
NSPredicate *predicate = [NSPredicate predicateWithFormat:
    @"ALL employees.salary > %f", salary];

答案 1 :(得分:1)

非常好奇如何解决这个问题我设置了一个小项目并创建了你正在使用的上下文。

NSDate *today = [NSDate date];
NSMutableArray *objects = [NSMutableArray array];

{
    NSArray *day = [NSArray arrayWithObjects:today, [today dateByAddingTimeInterval:20.0f], nil];
    NSDictionary *excludedDay = [NSDictionary dictionaryWithObject:day forKey:@"day"];
    NSDictionary *object = [NSDictionary dictionaryWithObject:excludedDay forKey:@"excludedDay"];

    [objects addObject:object];
}

{
    NSArray *day = [NSArray arrayWithObjects:[today dateByAddingTimeInterval:20.0f], nil];
    NSDictionary *excludedDay = [NSDictionary dictionaryWithObject:day forKey:@"day"];
    NSDictionary *object = [NSDictionary dictionaryWithObject:excludedDay forKey:@"excludedDay"];

    [objects addObject:object];
}


NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NONE excludedDay.day == %@", today];
NSArray *filtered = [objects filteredArrayUsingPredicate:predicate];

NSLog(@"%@", filtered);

这在以下时间给出了对象:

  1. 日数组为空
  2. 日期数组不包含“今日”日期
  3. 这不会在以下情况下给出对象:

    1. 日数组包含'今天'
      • 日数组中有多少个对象
      • 无关紧要