NSPredicate 不适用于核心数据中的抽象实体属性

Posted

技术标签:

【中文标题】NSPredicate 不适用于核心数据中的抽象实体属性【英文标题】:NSPredicate not working with abstract entity attributes in core data 【发布时间】:2013-06-22 22:21:09 【问题描述】:

我有一个核心数据类 SSSLicense,它具有名称和类型等属性。它继承自一个名为 SSSArchivableEntity 的抽象实体,该实体具有一个名为 isArchived 的布尔属性(等等)。

我已经从数据库中获取了完整的许可证实体集,现在正尝试根据类型和 isArchived 标志进行过滤。但是,尽管我的谓词有很多变体,但我无法得到有效的结果。

以下是相关代码:

    NSSet *licenses = [person licenseList] ;

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(licenseType like %@) AND (isArchived == NO)",
                           lType];
NSSet *filteredLicenses = [licenses filteredSetUsingPredicate:predicate];

如果我更改我的谓词以使用 SSSLicense 的另一个属性,例如名称(而不是 isArchived),则谓词有效。我什至在 SSSLicense 中添加了一个简单的布尔属性并成功使用它进行过滤。

这似乎与 isArchived 是抽象实体的属性这一事实有关。我需要做一些特别的事情来过滤继承的属性吗?

谢谢!

【问题讨论】:

尝试重命名属性。某些属性名称与 NSManagedObject 的内置属性冲突。 谢谢,但这没有用。我将属性名称更改为“fred”,但仍然得到相同的结果(没有匹配的对象)。 NSPredicate 不是NSString,您需要了解更多关于如何使用%K%@ 格式说明符作为谓词,或者您可以创建一个谓词使用更舒适的积木。 我尝试了许多变体,包括 %K 与直接字符串。我给出了上面的示例代码,因为它是最容易解释的。如果属性是具体实体的一部分,Apple 的示例代码显示两者都可以正常工作。只有当我测试的属性在抽象实体中时它才会失败。 我有一个类似的问题,但在抽象基础实体中有一个字符串属性。不知道为什么谓词会过滤掉所有内容。 【参考方案1】:

也许硬编码该值不起作用。我建议使用标准语法:

[NSPredicate predicateWithFormat:
    @"(licenseType like %@) && (isArchived = %@)", lType, @(NO)];

如果这不起作用,我将通过 sqlite3 命令行工具或 Firefox 中的 SQLite 管理器插件手动检查您的 isArchived 属性的值。也许您期望那里的值尚未持久化。

如果所有这些都得到验证,则可能是您读取错误的值或显示错误的值,尽管谓词确实有效。

【讨论】:

谢谢,上面的方法我试过了,还是不行。我知道有一个有效值,因为我在代码中添加了一些调试语句,通过调用 getter 方法手动测试集合中的对象(不使用谓词),它显示了正确的 YES/NO 值。跨度> 不确定我是否理解,因为谓词返回零个对象。如果我更改代码并将布尔值从抽象实体直接移动到具体实体中,则谓词有效。只有当我测试的属性在抽象实体中时,谓词才返回不结果。 我刚刚构建了一个简单的测试应用程序。这应该有效。也许还有其他事情正在发生。如果您改为搜索抽象实体,谓词是否有效? (即使您可能得到超出预期的结果。) 我又试了一次,发现问题似乎出在谓词和我的种子数据上。我以编程方式创建了一些种子数据。数据不适用于谓词。我在应用程序中创建的数据有效。种子数据使用 isArchived 的默认值(例如,不设置它),而应用程序代码明确将其设置为 NO。让我失望的是,对 isArchived 的调用对于种子数据和在应用程序中创建的数据都返回了 NO。在测试我的直接“if”测试的值时,谓词似乎更加特殊。感谢您的帮助!【参考方案2】:

我更喜欢 blocks 而不是 format,因此我会尝试这样的事情:

[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) 
    return ([[evaluatedObject licenseType] rangeOfString:lType].location == NSNotFound && [[evaluatedObject isArchived] boolValue] == NO);
];

【讨论】:

【参考方案3】:

事实证明,问题在于谓词如何通过 if 语句测试条件测试与直接测试。我的种子数据通过直接 setter 调用创建了许可证,我没有明确将 isArchived 设置为 NO。在应用程序中,创建许可证时正在设置它。因此,种子数据未能通过谓词返回。但是,如果我手动遍历该集合并通过“[license isArchived] == NO”进行测试,则种子数据和应用程序数据都会按预期返回。

我的猜测是,直接布尔测试会检查有效的“是”,如果没有,则假定“否”,而谓词明确检查 YES=1 NO=0(或者无论如何表示)。

【讨论】:

以上是关于NSPredicate 不适用于核心数据中的抽象实体属性的主要内容,如果未能解决你的问题,请参考以下文章

NSPredicate 用于检查核心数据中的 NULL 和空白字符串

NSPredicate 不适用于双值 (%f)?

NSPredicate 用于查询中的位置

核心数据 - NSPredicate 用于具有相同列且满足另一个条件的对象

带有核心数据对象的 NSPredicate

使用 NSPredicate 进行核心数据实体搜索