我对CoreData请求很不满意。用一些SQL派生的方法,我就能搞定。但在这里我需要一些帮助。
我有两个实体,有manyToMany关系。它看起来像这样。
Repeatable (name: String, type: Int16, entries: [Entry])
Entry (id: UUID, createdAt: Date, repeatables: [Repeatable])
我想得到一个重复数据的列表,它属于一个以上的条目,按关联数排序
在SQL中,它看起来像这样。
SELECT rep.Z_PK, COUNT(rep.Z_PK) as count FROM ZREPEATABLE AS rep
INNER JOIN Z_1REPEATABLES as link
ON rep.Z_PK = link.Z_2REPEATABLES
INNER JOIN ZENTRY AS entry
ON entry.Z_PK = link.Z_1ENTRIES
GROUP BY rep.Z_PK
HAVING count > 1
ORDER BY count DESC
编辑:我想出了这样一个办法(部分解决方案):我可以在swift中用Core Data做这个事情吗?
我想到了这个(部分解决方案)。
let somethingED = NSExpressionDescription()
somethingED.expression = NSExpression(forKeyPath: "[email protected]")
somethingED.name = "countSth"
somethingED.expressionResultType = .integer64AttributeType
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Repeatable")
fetchRequest.propertiesToFetch = ["name", somethingED]
fetchRequest.relationshipKeyPathsForPrefetching = ["entries"]
fetchRequest.resultType = .dictionaryResultType
fetchRequest.predicate = NSPredicate(format: "$countSth > 1")
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
do {
let result = try context.fetch(fetchRequest)
print(result)
} catch{
print("error fetching: \(error)")
}
这个解决方案的问题是... 我不知道如何排序。我总是以一个错误结束。而且这也不是group-by+有构造。所以,我想,好吧,如果这能行,我不需要group-by。但我还是想知道如何或者是否可以用group-by + having谓词?
编辑2:
所以在评论里 @pbasdf 链接了这个从WWDC 2019 (+1)。它完全描述了我的用例,并提供了一个完美的解决方案... ... 但是......它是针对iOS 13的,但我也想支持iOS 12(比如iPhone 6)。所以我最终想出了这个解决方案:有了一个 entriesCount
属性+在每次保存时更新该值.现在保存会慢一点,但读取会超快,因为在查询中不需要表连接、分组或计数。
public override func willSave() {
let newValue = Int16(self.entries?.count ?? 0)
if countEntries != newValue, changedValues()[#keyPath(Repeatable.countEntries)] == nil, !isDeleted {
countEntries = newValue
}
super.willSave()
}
是的,你可以这样做。你可以创建一个 NSFetchRequest 并定制其 sortDescriptors
和 predicate
属性来获得你想要的结果。
如果你正确设置了你的核心数据关系,就不需要手动指定 "内部连接 "之类的东西。你只需在数据模型中设置多对多的关系,然后就可以在你的谓词中直接访问这些关系。
我不知道你的整个查询是否完全可以翻译成一次取数,但没有必要限制自己。一旦你完成了你的fetch,你可以在一个管理对象上下文中做进一步的refinementprocessing。这就是CoreData ORM的全部意义,你只需要直接在对象上工作,而不用担心底层DB。