如何仅获取Core Data和NSPredicate中的多对多关系的子集

时间:2017-08-23 12:16:28

标签: swift core-data nspredicate

这个让我疯了......

我有一个涉及事件的模型(每个事件与RecordEntries有多对多的关系),如下所示:

Event <---recordEntries--->> RecordEntry

我想要做的是获取一个事件以及与特定ageGroup,gender和provinces匹配的所有相关recordEntries(过滤掉不匹配的recordEntries)。要清楚,我需要Event对象,但我不需要所有的recordEntries - 我只对Event中所有recordEntries的子集感兴趣。

所以我试着这样做:

let request = NSFetchRequest<Event>(entityName: "Event")
request.relationshipKeyPathsForPrefetching = ["recordEntries"]

request.predicate = NSPredicate(format: "SUBQUERY(%K, $r, $r.ageGroup == %i AND $r.gender == %@ AND $r.province IN %@).@count > 0", #keyPath(Event.recordEntries), ageGroupCode, userGender, ["CA", userProvince])

...我最终得到了所有记录(而不是匹配ageGroupCode,userGender和[“CA”,userProvinces]的记录。

我也尝试了以下内容:

let recordAgePredicate = NSPredicate(format: "ANY recordEntries.ageGroup == %i", ageGroupCode)
let recordGenderPredicate = NSPredicate(format: "ANY recordEntries.gender == %@", userGender)
let recordProvincePredicate = NSPredicate(format: "ANY recordEntries.province IN %@", ["CA", userProvince])

request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [
  recordAgePredicate, recordGenderPredicate, recordProvincePredicate
]

...这也返回了事件的所有记录(包括那些我不想要的记录)。

我在这里缺少什么?!?

1 个答案:

答案 0 :(得分:0)

这个答案归功于@ user1000,他指出了我正确的方向(并提供了几个代码片段来尝试)......

事实证明@pbasdf是对的 - 在对事件进行提取时,对其recordEntries关系的谓词没有影响。

@ user1000建议使用以下方法将以下方法添加到Event类:

func recordsFilteredFor(ageGroup: Int, province: [String], gender: String) -> Set<RecordEntry>{
    let pred = NSPredicate(format: "ageGroup == %i AND province IN %@ AND gender == %@", ageGroup, province, gender)
    let result = recordEntries?.filtered(using: pred)
    return result as! Set<RecordEntry>
}

有了这个,我可以通过查看event.recordsFilteredFor(...)而不是event.recordEntries来遍历事件并仅访问我想要的记录。

我不清楚这对性能有何影响。有了这个解决方案,我仍然最终获取超过我需要的内容,然后过滤掉这些内容,但我没有那么多记录要处理。

我将request.relationshipKeyPathsForPrefetching = ["recordEntries"]留在那里,认为我最好是急切加载所有关系,而不是在recordsFilteredFor方法中再次获取它们。我仍然需要仔细检查这是否有任何好处。一些初步的测试表明我仍然最终在recordsFilteredFor方法中触发了一个错误(这会让急切加载变得毫无意义)。

直到我找到更好的东西,看起来这将是我的解决方案......