【问题标题】:How to correctly setup a NSPredicate for a to-many relationship when using Core Data?使用 Core Data 时如何为一对多关系正确设置 NSPredicate?
【发布时间】:2010-11-23 18:47:45
【问题描述】:

我有一个核心数据模型,其中任务实体包含一个可选的多对多关系 ExcludedDays 到 ExcludedDay 实体。 ExcludedDay 的属性之一是 day,它是一个 NSDate 对象。 ExcludedDay 实体与 Task 实体具有相反的强制一对一关系。

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

我开始尝试

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 对象的属性 day 无关:用相应的 NSString 或等效的整数替换 day,我仍然面临同样的问题和不正确的行为。

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

【问题讨论】:

    标签: iphone core-data


    【解决方案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. day 数组为空
    2. day 数组不包含“今天”日期

    这不给对象当:

    1. day 数组包含“今天”
      • day 数组中有多少个对象并不重要

    【讨论】:

    • 不幸的是,这是一个完全不同的设置:我的上下文基于 Core Data 和 iPhone SDK 3.0 或 3.1。在遵循一对多关系时,Core Data 框架似乎没有正确处理谓词。我已经提交了一个错误,Apple 工程师正在处理它,但仍然没有得到他们的答复。
    • 那么这确实是一个核心数据中继问题,因为使用相同的谓词但没有核心数据它可以正常工作(正如我试图模仿相同的(与基金会相关的)上下文所看到的那样)跨度>
    【解决方案2】:

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

    本例中正确的谓词如下:

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

    在谓词中,子查询用于测试日期与您的测试日期匹配的相关排除事件的数量是否等于零。但是,文档具有误导性。以下是谓词编程指南中关于将谓词与一对多关系结合使用的内容。

    在关系中使用谓词

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

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

    如果要查找所有员工的工资都超过一定金额的部门,请使用 ALL 运算符,如下例所示:

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

    【讨论】:

    • 也许你知道如何用 NSExpresion 和 NSComparisonPredicate 类编写带有 SUBQUERY 的表达式?有了你的回答,我决定了我的问题:stackoverflow.com/questions/2006927/…Thanks
    • 非常感谢您的回答,真的很有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多