Core Data - NSPredicate 用于具有相同列且还满足另一个条件的对象

Core Data - NSPredicate for objects with identical column and also meet another condition

我正在寻找一个谓词来获取类型为 Entity 的所有托管对象,其值在 属性 sessionId 中重复,其中所有组的 ("groups" ,意思是 sessionId's are equal) contents' 标志在 属性 processed 中被设置为 YES 的托管对象。这可以(慢慢地)完成,但我正在寻找一种高效的单衬垫为此。谢谢

这是慢速方式:

NSFetchRequest *request = [NSEntityDescription entityForName:@"Entity"
                                      inManagedObjectContext:context];
NSArray *all = [context executeFetchRequest:request error:nil];
NSArray *sessionIds = [all valueForKeyPath:@"@distinctUnionOfObjects.sessionId"];
NSMutableArray *objects = [NSMutableArray array];
for (NSString *sessionId in sessionIds) {
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"sessionId == %@", sessionId];
    NSArray *inSession = [all filteredArrayUsingPredicate:predicate];
    for(id obj in inSession) {
         if(![obj valueForKey:@"processed"]) continue;
    }

    [objects arrayByAddingObjectsFromArray:processed];
}
NSLog(@"%@", objects);

由于布尔值存储为 0 和 1,因此所有行都具有 processed = YES 的组将具有 average(processed) = 1。因此,您可以使用 NSFetchRequestpropertiesToGroupByhavingPredicate 来获得满足您条件的 sessionId。然后需要第二次获取以获取具有任何这些 sessionIds:

Entity 对象
NSFetchRequest *fetch = [NSFetchRequest fetchRequestWithEntityName:@"Entity"];
fetch.resultType = NSDictionaryResultType;
fetch.propertiesToFetch = @[@"sessionId"];
fetch.propertiesToGroupBy = @[@"sessionId"];
fetch.havingPredicate = [NSPredicate predicateWithFormat: @"average:(processed) == 1"];
NSArray *resultsArray = [context executeFetchRequest:fetch error:nil];
NSArray *sessionIdArray = [resultsArray valueForKeyPath:@"sessionId"];
NSFetchRequest *newFetch = [NSFetchRequest fetchRequestWithEntityName:@"Entity"];
newFetch.predicate = [NSPredicate predicateWithFormat:@"name IN %@",sessionIdArray];
NSArray *finalResults = [context executeFetchRequest:newFetch error:nil];
NSLog(@"Final results, %@", finalResults);

抱歉,这不是单行。我将它留给您来确定它是否比您自己的代码更快。

编辑

要一次性完成所有操作,请使用 NSFetchRequestExpression 代替中间数组:

NSFetchRequest *fetch = [NSFetchRequest fetchRequestWithEntityName:@"Entity"];
fetch.resultType = NSDictionaryResultType;
fetch.propertiesToFetch = @[@"sessionId"];
fetch.propertiesToGroupBy = @[@"sessionId"];
fetch.havingPredicate = [NSPredicate predicateWithFormat: @"average:(processed) == 1"];
NSExpression *fetchExpression = [NSFetchRequestExpression expressionForFetch:[NSExpression expressionForConstantValue:fetch] context:[NSExpression expressionForConstantValue:context] countOnly:false];
NSFetchRequest *newFetch = [NSFetchRequest fetchRequestWithEntityName:@"Entity"];
newFetch.predicate = [NSPredicate predicateWithFormat:@"sessionId IN %@",fetchExpression];
NSArray *finalResults = [context executeFetchRequest:newFetch error:nil];
NSLog(@"Final results, %@", finalResults);

请注意,在我的(公认的微不足道的)测试设置中,这实际上 运行 比两次获取解决方案慢。

仅供参考,如果您使用 SQL调试构建设置来检查生成的 SQL,它看起来像这样:

SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZSESSIONID, t0.ZPROCESSED FROM ZENTITY t0 WHERE t0.ZSESSIONID IN (SELECT n1_t0.ZSESSIONID FROM ZENTITY n1_t0 GROUP BY n1_t0.ZSESSIONID HAVING avg( n1_t0.ZPROCESSED) = ? )