2011-05-07 86 views
8

我正在研究iphone应用程序,并且我已经使用Group和Contact对象设置了一个简单的多对多关系。一个组可以有很多联系人,联系人可以属于多个组。崩溃使用集合操作:核心数据iOS应用程序中的“ALL”

我想使用下面的谓词来选择特定联系人不属于的所有组。 (注:uid字段是我用来唯一标识接触实体字符串字段)

[NSPredicate predicateWithFormat:@"ALL contacts.uid != %@", contactUId] 

根据苹果的谓词编程指南中,所有集合操作是有效的,但我得到以下异常,表明这是一个不支持的断言:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unsupported predicate (null)' 

我可以使用类似的谓词来选择联系人确实已经属于这样看来,我拥有所有正确定义的关系和领域的使用该谓词的所有组。

[NSPredicate predicateWithFormat:@"ANY contacts.uid == %@", contactUId] 

例外构建谓语时被抛出而不是当我试图所以它似乎与我使用的,而不是核心数据支持的语法来实际执行读取请求。我究竟做错了什么?

+0

Ambrose,欢迎来到SO。你能否围绕谓词的定义包含更多的代码? – makdad 2011-05-07 16:00:07

+0

我不确定还需要包括什么。 predicateWithFormat:call中引发异常(与执行fetch过程相反),所以很明显问题与谓词有关,而与谓词无关。 – akrapacs 2011-05-09 13:00:57

+0

我在测试/示例应用程序中重新创建场景,并且正如我最初指出的那样,在调用[NSManagedObjectContext executeFetchRequest:error:]方法调用而不是在[NSPredicate predicateWithFormat:]调用中引发异常。 – akrapacs 2011-05-30 16:33:11

回答

0

基本的语法很好。这编译和运行在我的测试:

NSString *[email protected]"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以查看它的实际字符串转换值是什么。它在NSLog中显示的方式是它在谓词中出现的方式,因为它们都使用相同的字符串格式。

+0

我确实验证了值的变量是正确的。我甚至尝试使用硬编码的字符串作为参数而不是变量。此外,只要将谓词格式中的ALL改为ANY,它就可以正常工作,但它不会选择我想要的。我将在主项目之外创建一个测试项目,并尝试重新创建相同的场景。也许这会揭示出什么是错误的。 – akrapacs 2011-05-09 13:03:29

+0

'contactUid'转换为字符串是什么?你需要确保它没有奇怪的字符。作为一个极端的例子,如果将谓词格式保存为字符串,然后尝试将该字符串插入到谓词变量中,则会导致谓词无法初始化,因为谓词会尝试将字符串解析为它所表示的谓词,即字符像字符串中的'=',''''''''被解释为比较运算符而不仅仅是字符。 – TechZen 2011-05-09 13:10:30

+0

UID字符串如下所示:10474FD7-2FC8-44AA-85FA-3C7BA0773AC4。我尝试使用没有破折号的格式(例如:1001595484),结果相同。我在一个示例应用程序中重新创建了场景,并且无论UID格式如何,我都会得到相同的崩溃。 – akrapacs 2011-05-30 16:31:19

5

核心数据编程指南说

There are some interactions between fetching and the type of store. In the XML, binary, and in-memory stores, evaluation of the predicate and sort descriptors is performed in Objective-C with access to all Cocoa's functionality, including the comparison methods on NSString. The SQL store, on the other hand, compiles the predicate and sort descriptors to SQL and evaluates the result in the database itself.

它继续描述在使用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中的天真实现好得多。

无论什么值得,苹果开发者说here ALL在SQLite中不受支持,相反的文档是错误的。尽管这个文档在2013年仍然存在,所以似乎没有人对此做过任何事情。

无论如何,你其实应该做的是这样的:

NSFetchRequest *fetchRequest = ... 
NSArray *result = [moc executeFetchRequest:fetchRequest error:&err]; 
result = [result filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"ALL contacts.uid != %@", contactUId]]; 

这将在软件计算谓词。

0

Aggregate expressions are not supported by Core Data.

对于记录,上述警告是从(2013)NSExpression类参考,在the paragraph relative to Aggregate Expressions。事实上,一些运算符在SQL中可以被翻译时被支持(ANY,NONE)。