使用聚合操作崩溃:Core Data iOS应用程序中的“ALL”
我正在一个iPhone应用程序,我有一个简单的多对多关系设置组和联系对象。 一个组可以有很多联系人,联系人可以属于多个组。
我尝试使用以下谓词select特定联系人不属于的所有组。 (注意:uid字段是我用来唯一标识联系人实体的string字段)
[NSPredicate predicateWithFormat:@"ALL contacts.uid != %@", contactUId]
根据苹果的谓词编程指南,ALL聚合操作是有效的,但我得到以下exception,指出这是一个不受支持的谓词:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unsupported predicate (null)'
我可以使用一个类似的谓词来使用这个谓词来select一个联系人已经属于的所有组,所以看起来我具有正确定义的所有关系和字段。
[NSPredicate predicateWithFormat:@"ANY contacts.uid == %@", contactUId]
构造谓词时抛出exception,而不是当我试图实际执行获取请求,所以它似乎与我正在使用的语法而不是核心数据支持相关。 我究竟做错了什么?
核心数据编程指南说
抓取和商店types之间有一些相互作用。 在XML,二进制和内存存储中,谓词和sorting描述符的评估在Objective-C中执行,可以访问所有Cocoa的function,包括NSString上的比较方法。 另一方面,SQL存储将谓词和sorting描述符编译为SQL,并在数据库本身中评估结果。
它继续描述使用NSSQLiteStoreType的NSPredicate的一些其他限制,但是您在这里使用“ALL”是一个(未logging的)限制,它与获取请求如何发出SQL有关。
在底层,CoreData为您的模式生成三个表格:
- 一个联系表
- 组表
- 一个连接他们的连接表
所以当你打电话给myGroup.contacts,像这样的东西得到运行:
select * from Group join JOIN_TABLE on Group.pk == JOIN_TABLE.group_pk join Contact on JOIN_TABLE.contact_pk == Contact.pk where Group.pk == 12
在一个点字符后面有很多事情要做!
无论如何,要真正实现你的查询,你需要这样的东西。 我在一个实际的SQLite CD数据库上testing了这个,所以表名看起来很奇怪,但它仍然是可理解的:
select ZGROUP.Z_PK as outer_pk from ZGROUP where "myUID" not in (select ZCONTACT.ZUID as contact_uid from ZGROUP join Z_1GROUPS on Z_1GROUPS.Z_2GROUPS == ZGROUP.Z_PK join ZCONTACT on Z_1GROUPS.Z_1CONTACTS == ZCONTACT.Z_PK where ZGROUP.Z_PK == outer_pk)
我不是SQL专家,但是我的观察首先是这个查询将会很慢,其次是从我们开始的NSPredicate开始。 所以只有通过大量的努力,CD才能用SQL查询来完成你想要做的事情,而且它所提出的查询不会比ObjC中的一个简单的实现好得多。
对于任何有价值的东西,苹果公司的开发人员都说在SQLite中不支持ALL,相反的文档是错误的。 那个文档在2013年仍然存在,所以似乎没有人对此做过任何事情。
无论如何,你应该做的是这样的:
NSFetchRequest *fetchRequest = ... NSArray *result = [moc executeFetchRequest:fetchRequest error:&err]; result = [result filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"ALL contacts.uid != %@", contactUId]];
这将在软件中评估谓词。
基本的语法是好的。 这个编译和运行在我的testing中:
NSString *contactUId=@"steve"; NSPredicate *p=[NSPredicate predicateWithFormat:@"ALL contacts.uid != %@", contactUId]; NSLog(@"p = %@",p); //=> p = ALL contacts.uid != "steve"
contactUid
variables很可能是问题所在。 如果它没有值或者不能干净地转换为NSPredicate可以理解的string,那么会导致崩溃。 例如
NSString *contactUId; NSPredicate *p=[NSPredicate predicateWithFormat:@"ALL contacts.uid != %@", contactUId]; NSLog(@"p = %@",p);
…造成你描述的崩溃。
在将它分配给谓词之前,我会立即loggingcontactUid
以查看它的实际string可转换值是什么。 它在NSLog中显示的方式是它将出现在谓词中的方式,因为它们都使用相同的string格式。
Core Data不支持聚合expression式。
有关logging,上面的警告是从(2013)NSExpression类参考,在相对于聚合expression式的段落中 。 事实上,有些运算符在SQL中可以被翻译的时候被支持(ANY,NONE)。
- 我怎样才能在Swift中表示for循环的关键是NSString?
- 核心数据:尝试删除时出现“NSObjectInaccessibleException”。
- 如何使用当前的NSPersistentStore方法在本地和iCloud中创build可共享的Core Data .sqlite备份
- 关于Swift核心数据的指导3
- UITableView删除/添加行导致CoreData:严重的应用程序错误,如果在SplitViewController的MasterView中select了另一个对象
- iOS的崩溃'NSInternalInconsistencyException',原因:'语句仍然是'核心数据caching相关?
- 核心数据错误133020:保存中的问题合并:
- 只有当布尔条件满足,当restkit尝试更新logging时,才更新或保存被pipe理对象
- 是否有可能以编程方式生成核心数据结构?