NSPredicate 检测存在于多个实体关系中的一整组实体

Posted

技术标签:

【中文标题】NSPredicate 检测存在于多个实体关系中的一整组实体【英文标题】:NSPredicate to detect an entire set of entities being present in multiple entity relationships 【发布时间】:2018-08-03 20:35:17 【问题描述】:

给定这样的核心数据实体设置

实体A aB -> B(多对一) aC -> C(多对1) 儿童 -> 儿童(多对多) 实体B 儿童 -> 儿童(多对多) 实体C 儿童 -> 儿童(多对多) 实体儿童

我正在尝试进行查询以查找所有实体 A,以便在所有可访问的子项中找到一组子实体 TestChildren。类似于此示例的匹配 A 实体 A1

TestChildren设置

孩子1 孩子2 孩子3 Child4

A1实体

aB -> B1 aC -> C1 儿童 -> child1 -> child3 B1 实体 儿童 -> child2 C1 实体 儿童 -> child4

因此,所有 4 个孩子都已在每个班级的各种孩子关系中找到。

似乎要测试这些集合,我必须对每个 Children 关系执行子查询,但我认为我无法使用 NSPredicate 格式表达我想要的内容。也许它根本无法使用 NSPredicates?

我的一个想法是做这样的事情

  predicateString += "((SUBQUERY(aB.children, $child, $child in %@).@count + SUBQUERY(aC.children, $child, $child in %@).@count + SUBQUERY(children, $child, $child in $@).@count) == $@)"
  predicateVars.append(contentsOf: [testChildren, testChildren, testChildren, testChildren.count])

所有子关系中的匹配总数必须匹配。不幸的是,如果同一个孩子可能出现在多个 A、B 或 C 中,那么这将是不正确的,因为同一个孩子在两个不同的类别将允许总数不正确地匹配。

无论如何,在 NSPredicates 中加起来似乎是不可能的?

真正正确地做到这一点的唯一方法是能够在 3 个类中生成所有子级的总集合,但似乎没有办法在 NSPredicate 中表达这一点?

在更糟糕的情况下,我可以执行更简单的查询并对返回的结果执行更多逻辑,但理想情况下,我会尝试在查询中做尽可能多的繁重工作。

提前致谢

【问题讨论】:

如果所有子关系都是一对多的,那么一个子不能出现在多个 A、B 或 C 中。是否要检查 TestChildren 的所有 A 是否相同一种?还是我误解了这个问题? 你说得对,我把描述弄错了。我现在已经修改了。抱歉.. 它的 A -> B 和 A->C 都是多对一的关系,所有的孩子都是多对多的,你现在可以在原始问题文本中更清楚地看到。 如果有人感兴趣,我在这里添加了另一个使用类似但略有不同的实体层次结构的问题 - ***.com/questions/51753032/… 【参考方案1】:

谓词查找所有 A 和一个孩子:

NSPredicate(format:"aB.children contains %@ OR aC.children contains %@ OR children contains %@", child, child, child)

AND 谓词查找所有带有child1child2child3child4 的A:

var predicateArray:[NSPredicate] = []
for child in testChildren 
    let predicate = NSPredicate(format:"aB.children contains %@ OR aC.children contains %@ OR children contains %@", child, child, child)
    predicateArray.append(predicate)

let finalPredicate = NSCompoundPredicate(andPredicateWithSubpredicates:predicateArray)

【讨论】:

非常感谢您的建议。明天我会尝试一下,如果我能让它工作,我会接受答案!手指交叉!干杯! 这很好用。我最终将它重做为字符串谓词而不是复合谓词,我认为它们是等价的,并且字符串稍后更容易调试,因为您可以阅读整个谓词。我会把我的版本放在另一个答案中,但我已经接受了你的。奇怪的是为什么我们必须单独处理每个孩子,当我阅读 NSPredicate 文档时,看起来你应该能够像我试图做的那样使用实体容器。但无论我尝试什么,我都无法让它发挥作用,因为它工作得很好! 我想知道这些谓词的限制是什么......以字符串形式我确实想知道你可以将它推多远,与复合谓词类似,幸运的是我不希望有超过少数孩子要以这种方式处理.. 它不像会去 10 或 100 多个孩子,这只会是一团糟【参考方案2】:

上述 Willeke 答案的另一个版本是构建谓词描述为带有变量的字符串,如下所示

var predicateString:String = ""
var predicateVars:[Any] = []

for child in testChildren

  if (predicateString.count > 0)
  
    predicateString += " && "
  

  predicateString += "(aB.children contains %@ || aC.children contains %@ || children contains %@)"
  predicateVars.append(contentsOf: [child, child, child])

let predicate = NSPredicate(format: predicateString, argumentArray: predicateVars)

【讨论】:

以上是关于NSPredicate 检测存在于多个实体关系中的一整组实体的主要内容,如果未能解决你的问题,请参考以下文章

NSFetchedResultsController 和 NSPredicate 以及部分名称

使用 NSPredicate 的特定对象内的核心数据 NSFetchRequest

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

NSPredicate 用于两级深对多关系中的项目,无直接关系

NSPredicate 过滤关系

如何根据多对关系集是不是包含特定值使用 NSPredicate 进行过滤