如何使用中间模型格式化核心数据多对多谓词

How to format a core data many to many predicate with an intermediate model

我有以下核心数据模型:

我有一个包含特定 SkillGroup 的视图控制器。我想发出一个获取请求,其中包含该技能组中所有技能的记录。通常我会认为它会像

request.predicate = NSPredicate(format: "skill IN %@.skills", skillGroup!)

但是我需要创建中间“SkillGroupItem”模型,以便我可以跟踪 skillGroup 中每个技能的 displayIndex。我在想类似的东西:

request.predicate = NSPredicate(format: "ANY %@.skillGroupItems.skill = skillProgress.skill", skillGroup!)

因此任何 skillGroup 的 skillGroupItems 技能都等于记录 skillProgress object.skill...

但这会引发此错误:

CoreData: annotation: to-many relationship fault "skillGroupItems" for objectID 0xb9291ca50355a7c1 <x-coredata://33325602-3973-46E7-8400-45922DD97A05/SkillGroup/p1> fulfilled from database.  Got 1 rows
CoreData: sql: SELECT DISTINCT t0.Z_ENT, t0.Z_PK, t0.Z_OPT, t0.ZRECORDTYPE, t0.ZTIMESTAMP, t0.ZSKILLPROGRESS, t0.ZIMAGEFILENAME, t0.ZTEXT, t0.ZTHUMBNAILFILENAME, t0.ZVIDEOFILENAME FROM ZRECORD t0 JOIN ZSKILLPROGRESS t1 ON t0.ZSKILLPROGRESS = t1.Z_PK WHERE ? =  t1.ZSKILL ORDER BY t0.ZTIMESTAMP
2021-04-20 13:37:43.482875-0700 SweatNetOffline[38167:3014868] -[__NSSingleObjectSetI longLongValue]: unrecognized selector sent to instance 0x600002a69360
CoreData: annotation: total fetch execution time: 0.0013s for 0 rows.
2021-04-20 13:37:43.484519-0700 SweatNetOffline[38167:3014868] [error] error: SQLCore dispatchRequest: exception handling request: <NSSQLFetchRequestContext: 0x60000117d5e0> , -[__NSSingleObjectSetI longLongValue]: unrecognized selector sent to instance 0x600002a69360 with userInfo of (null)
CoreData: error: SQLCore dispatchRequest: exception handling request: <NSSQLFetchRequestContext: 0x60000117d5e0> , -[__NSSingleObjectSetI longLongValue]: unrecognized selector sent to instance 0x600002a69360 with userInfo of (null)
2021-04-20 13:37:43.503515-0700 SweatNetOffline[38167:3014868] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSSingleObjectSetI longLongValue]: unrecognized selector sent to instance 0x600002a69360'
*** First throw call stack:
(
    0   CoreFoundation                      0x00007fff20421af6 __exceptionPreprocess + 242
    1   libobjc.A.dylib                     0x00007fff20177e78 objc_exception_throw + 48
    2   CoreFoundation                      0x00007fff204306f7 +[NSObject(NSObject) instanceMethodSignatureForSelector:] + 0
    3   CoreFoundation                      0x00007fff20426036 ___forwarding___ + 1489
    4   CoreFoundation                      0x00007fff20428068 _CF_forwarding_prep_0 + 120
    5   CoreData                            0x00007fff25114346 -[NSSQLiteConnection execute] + 1416
    6   CoreData                            0x00007fff2538acfa _newFetchedRowsForFetchPlan_ST + 1234
    7   CoreData                            0x00007fff2537b1c5 _executeFetchRequest + 55
    8   CoreData                            0x00007fff252cd352 -[NSSQLFetchRequestContext executeRequestCore:] + 41
    9   CoreData                            0x00007fff253430a3 -[NSSQLStoreRequestContext executeRequestUsingConnection:] + 405
    10  CoreData                            0x00007fff2531468f __52-[NSSQLDefaultConnectionManager handleStoreRequest:]_block_invoke + 56
    11  CoreData                            0x00007fff2527bdbd __37-[NSSQLiteConnection performAndWait:]_block_invoke + 28
    12  libdispatch.dylib                   0x00000001094479c8 _dispatch_client_callout + 8
    13  libdispatch.dylib                   0x0000000109456bfe _dispatch_lane_barrier_sync_invoke_and_complete + 132
    14  CoreData                            0x00007fff2527bca3 -[NSSQLiteConnection performAndWait:] + 134
    15  CoreData                            0x00007fff253145a4 -[NSSQLDefaultConnectionManager handleStoreRequest:] + 273
    16  CoreData                            0x00007fff2531afd8 -[NSSQLCoreDispatchManager routeStoreRequest:] + 283
    17  CoreData                            0x00007fff2524b284 -[NSSQLCore dispatchRequest:withRetries:] + 161
    18  CoreData                            0x00007fff2524681e -[NSSQLCore processFetchRequest:inContext:] + 88
    19  CoreData                            0x00007fff2511a461 -[NSSQLCore executeRequest:withContext:error:] + 1072
    20  CoreData                            0x00007fff2522595a __65-[NSPersistentStoreCoordinator executeRequest:withContext:error:]_block_invoke.797 + 3219
    21  CoreData                            0x00007fff2521e02a -[NSPersistentStoreCoordinator _routeHeavyweightBlock:] + 222
    22  CoreData                            0x00007fff2511993e -[NSPersistentStoreCoordinator executeRequest:withContext:error:] + 1684
    23  CoreData                            0x00007fff25117ef2 -[NSManagedObjectContext executeFetchRequest:error:] + 885
    24  CoreData                            0x00007fff252da7d0 __43-[NSFetchedResultsController performFetch:]_block_invoke + 417
    25  CoreData                            0x00007fff2514ce63 developerSubmittedBlockToNSManagedObjectContextPerform + 154
    26  CoreData                            0x00007fff2514cd4a -[NSManagedObjectContext performBlockAndWait:] + 197
    27  CoreData                            0x00007fff252dcc13 -[NSFetchedResultsController _recursivePerformBlockAndWait:withContext:] + 145
    28  CoreData                            0x00007fff252da523 -[NSFetchedResultsController performFetch:] + 231
    29  SweatNetOffline                     0x0000000108ece722 $s15SweatNetOffline22ProgressViewControllerC11viewDidLoadyyF + 1122
    30  SweatNetOffline                     0x0000000108ecf8db $s15SweatNetOffline22ProgressViewControllerC11viewDidLoadyyFTo + 43
    31  UIKitCore                           0x00007fff23f5e36e -[UIViewController _sendViewDidLoadWithAppearanceProxyObjectTaggingEnabled] + 88
    32  UIKitCore                           0x00007fff23f62cd7 -[UIViewController loadViewIfRequired] + 1084
    33  UIKitCore                           0x00007fff23f630c1 -[UIViewController view] + 27
    34  UIKitCore                           0x00007fff23e82c37 -[UINavigationController _startCustomTransition:] + 1254
    35  UIKitCore                           0x00007fff23e991d6 -[UINavigationController _startDeferredTransitionIfNeeded:] + 684
    36  UIKitCore                           0x00007fff23e9a5e8 -[UINavigationController __viewWillLayoutSubviews] + 150
    37  UIKitCore                           0x00007fff23e7ad9e -[UILayoutContainerView layoutSubviews] + 217
    38  UIKitCore                           0x00007fff24bf8504 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2924
    39  QuartzCore                          0x00007fff27b1bc2b -[CALayer layoutSublayers] + 258
    40  QuartzCore                          0x00007fff27b2219d _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 575
    41  QuartzCore                          0x00007fff27b2df3f _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 65
    42  QuartzCore                          0x00007fff27a6d44c _ZN2CA7Context18commit_transactionEPNS_11TransactionEdPd + 496
    43  QuartzCore                          0x00007fff27aa4233 _ZN2CA11Transaction6commitEv + 783
    44  QuartzCore                          0x00007fff27aa53ef _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 79
    45  CoreFoundation                      0x00007fff2038f1f8 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
    46  CoreFoundation                      0x00007fff20389a77 __CFRunLoopDoObservers + 547
    47  CoreFoundation                      0x00007fff2038a01a __CFRunLoopRun + 1113
    48  CoreFoundation                      0x00007fff203896d6 CFRunLoopRunSpecific + 567
    49  GraphicsServices                    0x00007fff2c257db3 GSEventRunModal + 139
    50  UIKitCore                           0x00007fff24696cf7 -[UIApplication _run] + 912
    51  UIKitCore                           0x00007fff2469bba8 UIApplicationMain + 101
    52  SweatNetOffline                     0x0000000108e3d9fb main + 75
    53  libdyld.dylib                       0x00007fff2025a3e9 start + 1
    54  ???                                 0x0000000000000003 0x0 + 3
)
libc++abi.dylib: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSSingleObjectSetI longLongValue]: unrecognized selector sent to instance 0x600002a69360'
terminating with uncaught exception of type NSException
CoreSimulator 732.18.6 - Device: iPhone 11 (E5E1A675-AA38-45CE-A047-1C5569598381) - Runtime: iOS 14.4 (18D46) - DeviceType: iPhone 11

我被如何在这种情况下使用 ANY 绊倒了。所以任何 skillGroupItems 都有意义.. 但 ANY skillGroup.skillGroupItems.skill 对我来说似乎不好。您不能在 skillGroupItems 数组中查找 .skill。

关于如何完成此任务的任何建议?谢谢

使用您正在获取的实体(在您的例子中,Record)作为参考点来解析谓词。所以你会使用这个:

request.predicate = NSPredicate(format: "recordType == %@", givenRecordType)

根据属性recordType创建谓词,

request.predicate = NSPredicate(format: "skillProgress == %@", givenSkillProgressObject)

根据关系 skillProgress 创建谓词(如果 givenSkillProgress 是您已经获取的 SkillProgress 对象)。如果内存中没有SkillProgress对象,但知道要为其匹配的属性值,则可以使用相应的keypath表达式来引用相关对象的属性,eg:

request.predicate = NSPredicate(format: "skillProgress.isActive == YES")

将获取相关 SkillProgress 对象处于活动状态的那些 Record 对象。您可以通过在关键路径中使用其他元素来继续“遍历”关系树。所以:

request.predicate = NSPredicate(format: "skillProgress.skill.id == %@", givenSkillID)

将获取那些 Record 对象,其相关 SkillProgress 又与 Skill 相关,而 id 属性与 givenSkillID 相匹配。对于 skillGroupItems 关系(在 Skill 实体上),因为它是一对多的,您需要使用“ANY”来指示任何相关对象都应符合您的条件:

request.predicate = NSPredicate(format: "ANY skillProgress.skill.skillGroupItems == %@", givenSkillGroupItem)

然后最后一步是使用 SkillGroupItem 中的 skillGroup 关系来获取从 RecordSkillGroup 的完整密钥路径:

request.predicate = NSPredicate(format: "ANY skillProgress.skill.skillGroupItems.skillGroup == %@", givenSkillGroup)