2010-11-26 164 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匹配。