2010-11-26 162 views
3

我的應用程序具有類似於功能的智能文件夾:使用NSPredicateEditor設置謂詞並用於用提取請求填充文件夾。核心數據基於'有序'關係的屬性獲取

搜索中使用的實體具有多對多關係。這種關係是有序的,因爲索引存儲在目的實體中用於排序。

我的問題是,我想基於有序關係中的最後一個值構建規則,但我無法弄清楚如何構建一個謂詞來執行此操作,因爲關係不是數組。核心數據實際上並不知道訂單。

我對返回訂購商品的類有一個readonly屬性,但這似乎沒有幫助獲取請求,因爲該屬性在覈心數據存儲中不可用。

我能想到的唯一選擇是取消規範化並將最後的項目存儲在單獨屬性中排序的關係中。這是唯一的解決方案嗎?

回答

1

我不認爲有一種方法可以限制到n結果的謂詞,只在取請求級別。

除了像上面提到的那樣引用關係中的最後n個項目,您可以嘗試一個布爾屬性「lastN」並在您按照列表的順序(例如,在用戶啓動的排序或拖放重新排序)。

或者,你可以爲每個搜索的排序由您的排序關鍵的一點,有序下降,並且限制單獨取得請求(通過-setFetchLimit:)至ñ結果。

將此跟蹤爲關係或屬性有點「雜亂」,而提取限制更爲昂貴(因爲多次往返)。如果您的重新排序是通過一次性用戶操作完成的,則使用關係或屬性方法可能會更好,因爲工作是分期付款,而不是在一系列提取中一次完成。我自己並沒有找到更好的方法,並會密切關注這一點。 :-)

+0

我一直希望能夠通過單一的謂詞獲取來完成它,但我開始認爲它無法完成。我感覺使用額外的屬性 - 反規範化 - 可能是最好的方式,性能也是。 – 2010-11-26 21:34:46

+0

當然,每個對象搜索一次獲取請求的方法對於大量搜索對象來說是非常浪費和不合理的,但對於小列表來說,它可能是一個合理的命中。我個人使用「lastN」標誌方法。我認爲(但不要引用我)關係自動意味着與核心數據的多次往返。 – 2010-11-26 21:44:47

2

好吧,假設我已經正確地理解了問題,我會這樣做。假設你有兩個實體,TopEntity有一個(NSString *)名稱屬性和一個多對多的MyEntity關係,它有一個(NSString *)數據屬性和(NSInteger)次序屬性。

比方說你想匹配一個給定的字符串,而其myEntity所訂單滿足一定條件,那麼你可以用兩個謂詞做和NSFetchRequest像這樣將TopEntity對象....

NSManagedObjectContext *context = [self managedObjectContext]; 

// Create some top level entities 
TopEntity *aTop = [TopEntity insertInManagedObjectContext:context]; 
aTop.name = @"This is Your Name"; 
TopEntity *bTop = [TopEntity insertInManagedObjectContext:context]; 
bTop.name = @"This aint a Name";  
TopEntity *cTop = [TopEntity insertInManagedObjectContext:context]; 
cTop.name = @"This is My Name";  

// Add some data 
NSInteger i, len = 30; 
for(i=0; i<len; i++) { 
    // Create a new object 
    MyEntity *entity = [MyEntity insertInManagedObjectContext:context]; 
    entity.orderValue = i; 
    entity.data = [NSString stringWithFormat:@"This is some data: %d", i]; 
    if(i < 10) { 
     [aTop addObjectsObject:entity]; 
     [entity addTopObject:aTop]; 
    } else if (i < 20) { 
     [bTop addObjectsObject:entity]; 
     [entity addTopObject:bTop];    
    } else { 
     [cTop addObjectsObject:entity]; 
     [entity addTopObject:cTop];       
    } 
} 

// Save the context 
NSError *error = nil; 
[context save:&error]; 

// A predicate to match against the top objects 
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name BEGINSWITH %@", @"This is"]; 
// A predicate to match against the to-many objects 
NSPredicate *secondPredicate = [NSPredicate predicateWithFormat:@"ANY objects.order < %d", 5]; 
NSFetchRequest *fetch = [[NSFetchRequest alloc] init]; 
[fetch setEntity:[NSEntityDescription entityForName:@"TopEntity" inManagedObjectContext:context]]; 
[fetch setPredicate:predicate]; 
NSArray *result = [[context executeFetchRequest:fetch error:&error] filteredArrayUsingPredicate:secondPredicate]; 


for(TopEntity *entity in result) { 
    NSLog(@"entity name: %@", entity.name);   
} 

所以,基本上你可以用另一個謂詞來包裝你的獲取請求的結果並使用ANY關鍵字。

我不知道這是多高效,但它適用於這種情況。運行上述操作將輸出「This is Your Name」,即它與第一個TopEntity匹配。