我正在编写一个具有 iOS 和 macOS 目标的 100% SwiftUI 应用程序,使用 Core Data 和 NSPercientCloudKitContainer 来备份到 iCloud 并在登录到同一 AppleID 的设备之间进行同步。
涉及的三个实体是:餐食、份量、食物
每份餐食具有:
每个份量具有:
与我正在尝试的 准备一个谓词来过滤膳食,其中每个膳食部分包含某种食物或膳食直接包含某种食物。
所以我将提供一个实际的例子...
餐 1
包括...
部分
食物
部分与名称 Banana Smoothie 包含以下食物:
Meal 2
包含...
部分
食物
适用于 macOS目标,我使用相对较新的 Table
结构来呈现一个表格,其中列出了特定食品实体的所有餐食实体,包括一个或多个部分实体包含该特定食品实体的餐食实体。
如果我回头参考上面的示例,对于名为“Banana”的 Food 实体,我希望我的谓词能够过滤我的 FetchRequest
,以便名称为“Meal 1”和“Meal 1”的 Meal 实体能够被过滤。结果中包含“餐 2”。
@FetchRequest var meals: FetchedResults<Meal>
这是此 FetchRequest
的当前谓词...
let portions = NSSet(object: food.foodPortions as Any)
let predicatePartA = NSPredicate(format: "%@ IN mealFoods", food)
let predicatePartB = NSPredicate(format: "ANY %@ IN mealsPortions", portions)
let predicate = NSCompoundPredicate(orPredicateWithSubpredicates: [predicatePartA, predicatePartB])
其中 food 是 @ObservedObject var food: Food
mealFoods
和 mealsPortions
是来自每份 Meal
的 NSSet
多对多关系 to > 对象。
predicatePartA
工作正常,我怀疑是因为它是一个 Object
IN
对象的 NSSet
。
predicatePartB
不会崩溃,但它也无法解决任何问题,我怀疑是因为我提供的是一组而不是单个对象。
我已经尝试研究如何实现这一点已经有一段时间了,我能想到的最好的办法是操作员......
@distinctUnionOfSets
@"SUBQUERY()
...但除了这个网站< /a> 我几乎找不到关于如何实现它们的文档
UPDATE
在 @JoakimDanielson 的帮助下我尝试使用 SUBQUERY...
let predicatePartB = NSPredicate(format: "SUBQUERY(mealsPortions, $portion, $portion IN %@).@count > 0", portions)
并且
let predicatePartB = NSPredicate(format: "SUBQUERY(mealsPortions, $portion, $portion IN %@).@count != 0", portions)
这不会崩溃,但它没有提供预期的结果。有
什么建议吗?
还值得注意的是,我找到了一些更好的 文档Apple 支持此语法,但由于谓词不起作用,我仍然不确定该
init(forSubquery:usingIteratorVariable:predicate:)
语法是否正确。
SUBQUERY(collection_expression, variable_expression, predicate);
I'm writing a 100% SwiftUI app with iOS and macOS targets, using Core Data and NSPersistentCloudKitContainer
to backup to iCloud and sync between devices signed into the same AppleID.
The three entities involved are: Meals, Portions, Foods
Each Meal has:
- a many-to-many relationship with Portions
- a many-to-many relationship with Foods
Each Portion has:
- a many-to-many relationship with Foods
I'm attempting to prepare a predicate to filter meals where each meal portion contains a certain food OR the meal contains a certain food directly.
So I'll provide a practical example...
Meal 1
consists of...
Portions
- Banana Smoothie
- Egg Sandwich
Foods
The Portion with the name Banana Smoothie contains the following Foods:
Meal 2
consists of...
Portions
- Blueberry Smoothie
- Ham Sandwich
Foods
For the macOS target, I'm using the relatively new Table
structure to present a table that lists all Meal entities for a certain Food entity, including those Meal entities where one or more of the Portion entities contains that certain Food entity.
If I refer back to the above example, for the Food entity named "Banana", I'd want my predicate to filter my FetchRequest
such that Meal entities with names "Meal 1" & "Meal 2" are in the results.
@FetchRequest var meals: FetchedResults<Meal>
Here is the current predicate for this FetchRequest
...
let portions = NSSet(object: food.foodPortions as Any)
let predicatePartA = NSPredicate(format: "%@ IN mealFoods", food)
let predicatePartB = NSPredicate(format: "ANY %@ IN mealsPortions", portions)
let predicate = NSCompoundPredicate(orPredicateWithSubpredicates: [predicatePartA, predicatePartB])
where food is @ObservedObject var food: Food
and mealFoods
and mealsPortions
are NSSet
many-to-many relationships to from every Meal
object.
predicatePartA
works fine, I suspect because it is one single Object
IN
an NSSet
of objects.
predicatePartB
doesn't crash, but it also doesn't resolve any meals, I suspect because I'm providing a set instead of a single object.
I've attempted to research for some time now how this might be achieved and the best I can come up with are the operators...
@distinctUnionOfSets
@"SUBQUERY()
...but apart from this website there is little documentation I can find on how to implement them.
UPDATE
With help from @JoakimDanielson I've attempted to use SUBQUERY...
let predicatePartB = NSPredicate(format: "SUBQUERY(mealsPortions, $portion, $portion IN %@).@count > 0", portions)
AND
let predicatePartB = NSPredicate(format: "SUBQUERY(mealsPortions, $portion, $portion IN %@).@count != 0", portions)
Again this does not crash, but it does not provide the expected results for the fetch request.
Any suggestions please?
Also worth noting that I've found some better documentation by Apple that supports this syntax although, because the predicate isn't working, I still not sure it is correct.
init(forSubquery:usingIteratorVariable:predicate:)
with the syntax
SUBQUERY(collection_expression, variable_expression, predicate);
发布评论
评论(1)
简短的回答...
或者,如果我为
portions
准备一个计算属性...那么在创建谓词时,我不需要强制解开
可选 NSSet
...大多数读这篇文章的人可能不想知道细节,但尽管如此,我还是觉得有必要把它写下来,所以长答案是...
...分为两部分,或者至少承认帮助我的两个贡献者解决它。
第 1 部分
主要是@JoakimDanielson 确认
SUBQUERY
是解决方案的正确路径,并花时间为我的案例制定语法,并质疑最终结果是一个非常基本的错误,问题不是我的SUBQUERY
语法,而是实际上我准备在谓词字符串中使用的NSSet
的方式。我需要做的就是将...更改
为...
之后,我可以在创建谓词时强制将其解开,或者以其他方式准备一个计算属性(我选择的解决方案) - 如上面简短答案中所详述。
这只是一个错误,因为我对集合
NSSet
和Set
的理解不够。回顾一下 swift.org 文档 对我有帮助。第 2 部分
其次,这个 SO Q&A“如何使用 BETWEEN 子句创建 CoreData SUBQUERY?”以及对此聪明的引用标题为“SUBQUERY 没那么可怕”作者:@MaciekCzarnik。
我经历了减少必要迭代的过程,直到我可以逐行比较 SUBQUERY 语法。虽然它实际上并没有解决我的问题,但这确实鼓励我尝试多种谓词语法替代方案,直到我返回对
SUBQUERY
的理解并能够确认原始语法是正确的。它为我提供了我的大脑可以理解和处理的示例类型,以加深对SUBQUERY
实际工作原理的理解。因为您当前没有更好的内容可阅读...
可以简化为 _
可以简化为 _
可以简化为 _
iterationFour == predicatePartB
Short answer...
OR, if I prepare a computed property for
portions
...then in the creation of the predicate I'm not required to force unwrap the
optional NSSet
...Most people reading this probably won't want to know the detail but nonetheless I feel compelled to write this down, so the long answer is...
... in two parts, or at least recognises two contributors who helped me solve it.
Part 1
Primarily @JoakimDanielson for confirming that
SUBQUERY
was the right path to a solution and for taking the time to work out the syntax for my case and also for questioning what eventually turned out to be a very basic error, the problem was not mySUBQUERY
syntax but in fact the manner in which I was preparing theNSSet
that I used in the predicate string.All I needed to do was change...
to...
after which I could either force unwrap it in the creation of the predicate, or otherwise prepare a computed property (the solution I chose) - as detailed above in the short answer.
This was simply an error as a result of my inadequate understanding of the collections
NSSet
andSet
. A refresher of the swift.org docs helped me.Part 2
Secondly this SO Q&A "How to create a CoreData SUBQUERY with BETWEEN clause?" and the reference to this clever article titled "SUBQUERY Is Not That Scary" by @MaciekCzarnik.
I went through the process of reducing the necessary iteration until I could line for line compare the SUBQUERY syntax. While it didn't actually solve my problem, this did encourage me to try numerous predicate syntax alternatives until I returned with an understanding of
SUBQUERY
and was able to confirm the original syntax was correct. It provided me with the type of example my brain can comprehend and work through to develop an understanding of howSUBQUERY
actually works.Because you have nothing better to read at the current moment in time...
can be simplified to _
can be simplified to _
can be simplified to _
iterationFour == predicatePartB