2011-05-07 40 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)。