我正在使用iphone应用程序,并且我使用Group和Contact对象设置了简单的多对多关系。一个组可以有多个联系人,联系人可以属于多个组。
我尝试使用以下谓词选择特定联系人不属于的所有组。 (注意:uid字段是我用来唯一标识联系人实体的字符串字段)
[NSPredicate predicateWithFormat:@"ALL contacts.uid != %@", contactUId]
根据Apple的谓词编程指南,ALL聚合操作有效但我得到以下异常,表明这是一个不受支持的谓词:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unsupported predicate (null)'
我可以使用类似的谓词来选择联系人已经使用此谓词所属的所有组,因此看起来我已正确定义了所有关系和字段。
[NSPredicate predicateWithFormat:@"ANY contacts.uid == %@", contactUId]
构造谓词时会引发异常,而不是在我尝试实际执行获取请求时抛出异常,因此它似乎与我使用的语法相关而不是核心数据支持。我做错了什么?
答案 0 :(得分:5)
核心数据编程指南说
提取和商店类型之间存在一些交互。在XML,二进制和内存存储中,谓词和排序描述符的评估在Objective-C中执行,可以访问所有Cocoa的功能,包括NSString上的比较方法。另一方面,SQL存储将谓词和排序描述符编译为SQL,并在数据库本身中评估结果。
它继续描述了使用NSPredicate和NSSQLiteStoreType的一些其他限制,但是你在这里使用“ALL”是一个(未记录的)限制,它与获取请求如何发出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数据库上测试了这个,所以表名看起来很奇怪,但它仍然应该是可理解的:
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中的天真实现好得多。
对于任何它的价值,Apple开发人员说here所有在SQLite中都不支持,而相反的文档是错误的。该文件仍然存在于2013年,因此似乎没有人对此做过任何事情。
无论如何,你应该做的事情是这样的:
NSFetchRequest *fetchRequest = ...
NSArray *result = [moc executeFetchRequest:fetchRequest error:&err];
result = [result filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"ALL contacts.uid != %@", contactUId]];
这将评估软件中的谓词。
答案 1 :(得分:0)
基本语法很好。这在我的测试中编译并运行:
NSString *contactUId=@"steve";
NSPredicate *p=[NSPredicate predicateWithFormat:@"ALL contacts.uid != %@", contactUId];
NSLog(@"p = %@",p);
//=> p = ALL contacts.uid != "steve"
问题很可能是contactUid
变量。如果它没有值或者没有干净地转换为NSPredicate理解的字符串的值,那么它将导致崩溃。例如。
NSString *contactUId;
NSPredicate *p=[NSPredicate predicateWithFormat:@"ALL contacts.uid != %@", contactUId];
NSLog(@"p = %@",p);
...导致你描述的崩溃。
我会在将contactUid
分配给谓词之前立即记录{{1}},以查看其实际的字符串可转换值。它在NSLog中显示的方式是它在谓词中的显示方式,因为它们都使用相同的字符串格式。
答案 2 :(得分:0)
Core Data不支持聚合表达式。
对于记录,上面的警告来自{2013} NSExpression类参考,the paragraph relative to Aggregate Expressions。事实上,当一些运算符可以在SQL中翻译时,它们被支持(ANY,NONE)。