NSPredicate 在核心数据中的多对多关系

Posted

技术标签:

【中文标题】NSPredicate 在核心数据中的多对多关系【英文标题】:NSPredicate on multiple to-many relationships in Core Data 【发布时间】:2016-03-12 21:17:51 【问题描述】:

我有一个NSPredicate,其中包含多个聚合过滤器,这会引发异常。

我有以下核心数据模型:

我想挑选那些ApparelItems,其中任何coloursrgb 为13576743,并且所有pickspickTime 早于给定的NSDate

我创建谓词的代码是:

let request = NSFetchRequest(entityName: "ApparelItem")
var predicates = [NSPredicate]()

predicates.append(NSPredicate(format: "ANY colours.rgb = 13576743"))

// find the NSDate representing midnight x days ago
let cal = NSCalendar.currentCalendar()
if let xDaysAgo = cal.dateByAddingUnit(.Day, value: -2, toDate: NSDate(), options: [])

    let midnightXDaysAgo = cal.startOfDayForDate(xDaysAgo)

    predicates.append(NSPredicate(format: "(ALL picks.pickTime < %@)", midnightXDaysAgo))


request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: predicates)

let searchData = try? objectContext.executeFetchRequest(request)

我得到以下异常:

Exception name=NSInvalidArgumentException, reason=Unsupported predicate (ANY colours.rgb == 13576743) AND ALL picks.pickTime < CAST(479347200.000000, "NSDate")

我试过了:

    每个单独的谓词都可以正常工作。即ANY colours.rgb = ... 有效,ALL picks.pickTime &lt; ... 也有效。它们只是在组合到同一个查询中时不起作用。

    将两个 using 组合成一个查询,与 AND 链接,而不是使用 NSCompoundPredicate。结果是一样的。

核心数据是否可能根本不支持对多个一对多关系进行过滤?那会显得很奇怪。在什么情况下我应该怎么做?

【问题讨论】:

一种可能的出路,取决于问题表的基数,是使用filteredArrayUsingPredicate在内存中的第二个核心数据中进行最具选择性的过滤 谢谢...同意这是可能的,但它似乎真的效率低下。一方面(尽管上面的代码中没有显示,这是一个简化版本)我实际上只是在询问其ManagedObjectIds 的核心数据。因此,我实际上并没有要处理的对象。同样,这显然是我可以改变的,但我这样做是为了保持低内存使用率。 你试过使用子查询吗? 尝试单独使用每个谓词,看看其中一个是否负责,或者是否将它们混合在一起导致问题 【参考方案1】:

或许可以试试SUBQUERY() 换成NSPredicate

下面的代码是我从一些猜测中得出的,不太确定它是否有效。通常,对于NSPredicate 的一对多查询子句,我需要多次反复试验。

var predicates = [NSPredicate]()
predicates.append(NSPredicate(format: "SUBQUERY(colours, $colour, ANY $colour.rgb = 13576743).@count > 0"))
let cal = NSCalendar.currentCalendar()
if let xDaysAgo = cal.dateByAddingUnit(.Day, value: -2, toDate: NSDate(), options: []) 
    let midnightXDaysAgo = cal.startOfDayForDate(xDaysAgo)
    predicates.append(NSPredicate(format: "SUBQUERY(picks, $pick, ALL $pick.pickTime < %@).@count > 0", midnightXDaysAgo))

【讨论】:

这似乎行得通。作为参考,我只需要将一个谓词更改为子查询。所以我将日期更改为predicates.append(NSPredicate(format: "SUBQUERY(picks, $pick, $pick.pickTime &gt; %@).@count = 0", midnightXDaysAgo))(与您所拥有的略有不同,但概念相同。)感谢您的回答。【参考方案2】:

颜色和选择是两个不同的实体,因此您应该能够在不使用SUBQUERY 的情况下同时进行过滤。一个谓词或一个复合谓词都应该没问题。

从错误消息看来,日期可能有问题。请检查您的托管对象子类中是否有预期的数据类型。如果您在创建子类时使用“原始值”,则需要NSTimeInterval 而不是NSDate

【讨论】:

以上是关于NSPredicate 在核心数据中的多对多关系的主要内容,如果未能解决你的问题,请参考以下文章

具有多对多关系的核心数据 NSPredicate

核心数据 - 从多对多关系构建 NSPredicate

具有多对多关系的核心数据 - 在 SUBQUERY 中使用 ALL 创建 NSPredicate

如何在 IOS Swift 中获取核心数据中的多对多关系?

核心数据:获取特定对象的多对多关系中的所有实体?

多对多 NSPredicate 与 NSFetchedResultsController