核心数据 - NSPredicate 用于具有相同列且满足另一个条件的对象
Posted
技术标签:
【中文标题】核心数据 - NSPredicate 用于具有相同列且满足另一个条件的对象【英文标题】:Core Data - NSPredicate for objects with identical column and also meet another condition 【发布时间】:2015-11-11 21:09:27 【问题描述】:我正在寻找一个谓词来获取Entity
类型的所有托管对象,其值在属性sessionId
中重复,其中所有组(“组”,表示sessionId
相等的托管对象) 属性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);
【问题讨论】:
给我们看一些代码。你试过什么? 这是一个开放式问题——不是“请修复我的代码” @Skyler - 也许你应该听听 Cliff 的建议。至少显示“缓慢”的方式,因为您的描述令人困惑且不清楚。 “其值在列中重复”是什么意思? “处理列中所有组的内容标志的位置”应该是什么意思?此外,也许您在评论中使用了错误的术语,但开放式问题不适合堆栈溢出:***.com/help/dont-ask @Jody 添加示例代码 你的方法有多“慢”?你是怎么测量的? 【参考方案1】:由于布尔值存储为 0 和 1,因此所有行都具有 processed = YES
的组将具有 average(processed) = 1
。因此,您可以使用NSFetchRequest
的propertiesToGroupBy
和havingPredicate
来获得满足您条件的sessionId
s。然后需要第二次获取以获取具有任何 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);
请注意,在我的(诚然微不足道的)测试设置中,这实际上比两次获取解决方案运行得更慢。
仅供参考,如果您使用 SQLDebug 构建设置来检查生成的 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 HAVG(n1_t0.ZPROCESSED) = ?)
【讨论】:
感谢您的回复。这可以一次而不是两次完成吗?我想将尽可能多的计算分配到 SQLite 级别而不是 CocoaTouch 层 有趣的是你应该问 - 几天前我在研究另一个问题时才发现。我会更新我的答案。以上是关于核心数据 - NSPredicate 用于具有相同列且满足另一个条件的对象的主要内容,如果未能解决你的问题,请参考以下文章
NSPredicate 获取具有 NSDate 日期范围内的日期属性的核心数据对象
保存核心数据相关数据并使用具有多个实体的 NSPredicate 和 NSFetchedResultsController 检索