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
。因此,您可以使用 NSFetchRequest
的 propertiesToGroupBy
和 havingPredicate
来获得满足您条件的 sessionId
。然后需要第二次获取以获取具有任何这些 sessionId
s:
的 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) = ? )
我正在寻找一个谓词来获取类型为 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
。因此,您可以使用 NSFetchRequest
的 propertiesToGroupBy
和 havingPredicate
来获得满足您条件的 sessionId
。然后需要第二次获取以获取具有任何这些 sessionId
s:
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) = ? )