【问题标题】:How do I create a FetchRequest predicate for a child entity where the parent entity satisfies a NSPredicate如何为父实体满足 NSPredicate 的子实体创建 FetchRequest 谓词
【发布时间】:2020-09-27 16:42:07
【问题描述】:

我有两个核心数据实体:ParentChildParent 有一个属性 children 用于子集

每个Child 都有一个parent 属性将其链接到其父级,以及一个age 属性。 (我的数据比这更复杂,但这与问题无关)

我有一个NSPredicate 用于选择一组父母的Parent 实体和一个NSPredicate 用于根据年龄选择实体的Child 实体

我想要做的是为FetchRequest<Child> 构造一个NSPredicate,它返回满足两个单独谓词的Child 实体集

我知道我可以检索满足其谓词 ('parents') 的 Parent 实体数组,然后有一个类似于 NSPredicate(format: "parent IN %@", parents) 的子谓词,并将其包含在复合 AND 与子谓词中,但是有可能是数百名父母遇到他们的谓词,而在我看来,有两个单独的查询是一个但不重要的事情。

FetchRequest 必须是 FetchRequest<Child>,因为它用于 SwiftUI 视图,所以我不能只构建结果数组。

我怀疑我可以使用 SUBQUERY 谓词来做到这一点,但我不知道如何将父谓词嵌入到 SUBQUERY 中。我在Parent 实体的谓词字符串中收到类似Problem with subpredicate TRUEPREDICATE 的错误。

希望这是有道理的?有什么想法或建议吗?

谢谢

【问题讨论】:

  • 父实体的谓词是什么?
  • 它是由一组用户输入标准生成的谓词,因此它会有所不同。在我询问的查询中,我通过一个返回 NSPredicate 的函数访问它。
  • 每个孩子只有一个父母?
  • 是的,它是一个 -> 许多(父母 -> 孩子)

标签: swift core-data nspredicate


【解决方案1】:

如果从ChildParent 的关系是一对一,那么就不需要SUBQUERY。在父谓词的格式字符串中(您可以使用predicateFormat 获得),您可以将字符串中的每个父属性名称替换为子属性的键路径,即

attribute 变为 parent.attribute

然后可以使用NSCompoundPredicateandPredicateWithSubpredicates 将生成的谓词与子谓词组合。

如果解析 predicateFormat 不切实际,另一种选择是使用NSFetchRequestExpression 将一次获取的结果作为参数传递给另一个(它被转换为 SQL 子选择)。像这样的:

let parentFetch = Parent.fetchRequest()
parentFetch.predicate = parentPredicate // your existing predicate to fetch the parent objects
parentFetch.resultType = .managedObjectIDResultType
let ctxtExp = NSExpression(forConstantValue: managedObjectContext)
let fetchExp = NSExpression(forConstantValue: parentFetch)
let fre = NSFetchRequestExpression.expression(forFetch: fetchExp, context: ctxtExp, countOnly: false) 
let childFetch = Child.fetchRequest()
let subPredicate = NSPredicate(format:"parent IN %@",fre)
let combinedPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [subPredicate, childPredicate]) // childPredicate is you existing predicate to fetch the correct Child objects
childFetch.predicate = combinedPredicate
... proceed to execute the fetch against the relevant context

【讨论】:

  • 但是,父谓词最多可以包含大约 10 个属性,这些属性具有应用程序用户在运行时设置的不同匹配条件,因此可靠地搜索和替换谓词字符串中每个属性名称的公式并非易事并且在运行时可能容易出错。如果有办法做到这一点,我宁愿使用未更改的父谓词,因为这已经过全面测试
  • 谢谢,我认为这看起来很有希望,特别是如果它被转换为 SQL 子查询。我明天试试(我在英国,所以现在已经很晚了!)
  • 我不确定这是否可行 - 子查询抛出异常,抱怨它无法生成 SQL:*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'unimplemented SQL generation for predicate : (parent IN FETCH(<NSFetchRequest: 0x60000127a610> (entity: Parent; predicate: (startDate >= CAST(599529600.000000, "NSDate") AND (activityType == "Ride")); sortDescriptors: (( )); type: NSManagedObjectIDResultType; includesPropertyValues: NO; ), <NSManagedObjectContext: 0x600000214b60>, NO))'
  • 奇怪。你能展示你的实体定义和父谓词吗?
  • 我的错误:再次查看它,当我复制您建议的代码时,我没有将字符串“parent IN ...”更改为子实体上的实际父实体属性名称(它是不是'父母'...)。刚刚解决了这个问题,它工作得很好!感谢您的建议,我学到了一些新东西......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-16
  • 2019-11-25
  • 1970-01-01
相关资源
最近更新 更多