2012-11-07 46 views
5

對於我的生活,我似乎無法得到這個工作。你如何構造NSFetchRequest的setHavingPredicate謂詞?

假設我們的實體是一個具有狀態字段和訂單字段的管理對象。

我該如何處理讓所有有序訂單具有多個相同的訂單?

請不要告訴我只要在主謂語中使用@count做子查詢,因爲我知道這個解決方案,這篇文章的重點是要理解如何在覈心數據中使用謂詞,反正可能比子查詢更快。 (除非你解釋爲什麼我不能使用having子句)

以下代碼將返回帶有每個訂單號的訂單數量的字典數組。我想要的是能夠添加一個having子句來限制我的請求,只返回表示那些次數大於1的訂單對象的字典。

這是迄今爲止的代碼,謂:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
NSEntityDescription *entity = [NSEntityDescription entityForName:@"OrderedEntry" 
              inManagedObjectContext:context]; 
[fetchRequest setEntity:entity]; 
[fetchRequest setResultType:NSDictionaryResultType]; 

NSPredicate *predicate = [NSPredicate predicateWithFormat: 
       @"(status == %@)",[NSNumber numberWithInt:EntryStatusAlive]]; 


[fetchRequest setPredicate:predicate]; 


NSExpression *keyPathExpression = [NSExpression expressionForKeyPath: @"order"]; // Does not really matter 
NSExpression *maxExpression = [NSExpression expressionForFunction: @"count:" 
                 arguments: [NSArray arrayWithObject:keyPathExpression]]; 
NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init]; 
[expressionDescription setName: @"orderCount"]; 
[expressionDescription setExpression: maxExpression]; 
[expressionDescription setExpressionResultType: NSInteger32AttributeType]; 

[fetchRequest setPropertiesToFetch: [NSArray arrayWithObjects:expressionDescription,@"order",nil]]; 


[fetchRequest setPropertiesToGroupBy:[NSArray arrayWithObjects:@"order",nil]]; 
//[fetchRequest setHavingPredicate:[NSPredicate predicateWithFormat:@"@count > 1"]]; 
//[fetchRequest setHavingPredicate:[NSComparisonPredicate predicateWithLeftExpression:maxExpression rightExpression:[NSExpression expressionForConstantValue:[NSNumber numberWithInteger:1]] modifier:NSDirectPredicateModifier type:NSGreaterThanPredicateOperatorType options:NSCaseInsensitivePredicateOption]]; 

NSError *error; 

NSArray * array = [context executeFetchRequest:fetchRequest error:&error]; 
+1

你有沒有得到這樣一個答案?我發現了很多對setHavingPredicate的無用參考,它們沒有提供這個謂詞的格式。沒有工作的例子,沒有任何我已經嘗試過的工作... –

+2

@ChristopherKing沒有,我基本放棄了,網上沒有任何信息,而蘋果網絡論壇也沒有多大幫助。我真的相信沒有人會使用它,因爲通過正常獲取然後通過過濾器或通過循環手動移動數據來構建Having謂詞的相同功能非常簡單。我們想知道,因爲總是有'正確的方式'去做某些事情,特別是如果提供了API的話。 – thewormsterror

回答

0

首先,每當我嘗試一些類似於你在做什麼,我得到你不能傳遞一個一對多的關係,setPropertiesToFetch:錯誤。 NSFetchRequest documentation支持:「屬性描述可能代表屬性,一對一關係或表達式。」「這就是問題1。

問題2是你看不到通過一對多的關係(這在文檔中沒有明確說明,但你得到相同的錯誤,這也是有道理的)。

從屬性中刪除「訂單」以獲取。按屬性分組。修改你的主謂詞只包含你分組的那些屬性(或者只是刪除它)。在你的謂詞中指定「順序」。

[fetchRequest setPropertiesToGroupBy: @[ @"???" ]]; 
[fetchRequest setHavingPredicate: [NSPredicate predicateWithFormat: @"[email protected] > 1"]]; 

現在你會看到該請求將工作,但結果可能不正是您期望:

- NSArray 
    - NSDictionary { status = @"alive", orderCount = "4" } 
    - NSDictionary { status = @"alive", orderCount = "9" } 
    - NSDictionary { status = @"alive", orderCount = "2" } 
    - etc... 

NSDictionaryResultType實際上不會給你任何東西通過識別這些對象 - 它只是給你的價值。

因此,您的下一步是取回那些OrderedEntry對象的ID。訣竅是include an expression這將讓你回到NSManagedObjectID作爲每個字典中的關鍵。

我不知道這是否會給你帶來改進的性能(而不僅僅是將它與主謂詞聯繫起來)。根據我的經驗,您可以通過創建單例NSPredicates並使用替代變量來設置每次獲取來改善獲取性能。謂詞解析可能很昂貴。

字典結果類型可能是一個痛苦。通常只是構建一個好的謂詞更好。我只傾向於將它們用於表達式(即,在返回值的圖上執行統計類型計算)。如果你看看屬性的所有限制,以獲取和分組以及謂詞限制,這似乎是蘋果打算的。我甚至不確定通過分組和使用有謂詞來做你想做的事情是可能的 - 例如,你打算怎樣分組?如果按狀態(您需要將其分組以包含在謂詞中),是不是會摺疊所有的OrderEntries,並且您不會獲得單獨的objectID和orderCounts?最好堅持這個主謂詞,而不是分組和謂詞。

+0

我不明白你在說什麼,setPropertiesToFetch:我在這裏做錯了什麼?我有一個屬性「順序」和expressionDescription這是一個表達式。 – thewormsterror

+0

問題2我的訂單是一個屬性,而不是一個關係,所以我可以根據我的理解進行分組。 – thewormsterror

+0

那麼您如何計算一個屬性呢?爲了你的上面的例子,順序必須是多對多的關係才能做出任何意義。 – karwag

1

我結束了這是怎麼回事的人感興趣

-(BOOL)ordersAreSaneOnDay:(NSNumber*)dayNumber forUser:(User*)user inContext:(NSManagedObjectContext*)context { 
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
NSEntityDescription *entity = [NSEntityDescription entityForName:@"BasicEntry" 
              inManagedObjectContext:context]; 
[fetchRequest setEntity:entity]; 
[fetchRequest setResultType:NSDictionaryResultType]; 

NSPredicate *predicate = [NSPredicate predicateWithFormat: 
       @"(status == %@) && ((type != %@) && (type != %@) && (dayNumber == %@)) && ((user == NIL) || (user == %@))",[NSNumber numberWithInt:EntryStatusAlive],[NSNumber numberWithInt:EntryTypeTask],[NSNumber numberWithInt:EntryTypeCompletedTask],dayNumber,user]; 


[fetchRequest setPredicate:predicate]; 


NSExpression *keyPathExpression = [NSExpression expressionForKeyPath: @"order"]; // Does not really matter 
NSExpression *maxExpression = [NSExpression expressionForFunction: @"count:" 
                 arguments: [NSArray arrayWithObject:keyPathExpression]]; 
NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init]; 
[expressionDescription setName: @"orderCount"]; 
[expressionDescription setExpression: maxExpression]; 
[expressionDescription setExpressionResultType: NSInteger32AttributeType]; 

[fetchRequest setPropertiesToFetch: [NSArray arrayWithObjects:expressionDescription,@"order",nil]]; 
[expressionDescription release]; 

[fetchRequest setPropertiesToGroupBy:[NSArray arrayWithObjects:@"order",nil]]; 
//[fetchRequest setHavingPredicate:[NSPredicate predicateWithFormat:@"[email protected] > 1"]]; 
//[fetchRequest setHavingPredicate:[NSComparisonPredicate predicateWithLeftExpression:maxExpression rightExpression:[NSExpression expressionForConstantValue:[NSNumber numberWithInteger:1]] modifier:NSDirectPredicateModifier type:NSGreaterThanPredicateOperatorType options:NSCaseInsensitivePredicateOption]]; 

NSError *error; 

NSArray * array = [context executeFetchRequest:fetchRequest error:&error]; 
array = [array filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"orderCount > 1"]]; 
//NSLog(@"it worked %@",array); 
[fetchRequest release]; 

if ([array count]) return FALSE; 
return TRUE; 

}