NSPredicate Core Data iOS 中的子查询

Posted

技术标签:

【中文标题】NSPredicate Core Data iOS 中的子查询【英文标题】:Subquery in NSPredicate Core Data iOS 【发布时间】:2013-08-26 21:49:33 【问题描述】:

我想创建一个类似于 SQL 中的等价谓词:

select f.type, f.variety, f.price
from (
   select type, min(price) as minprice
   from fruits group by type
) as x inner join fruits as f on f.type = x.type and f.price = x.minprice;

但是看到我无法使用带有核心数据块的谓词对它进行排序,我想知道如何使用 [NSPredicate predicateWithFormat:] 方法来编写它。

需要说明的是,我有一个表格“水果”,列有类型、品种和价格。我想为每种不同类型选择一行,其中价格是其类型中最低的。

【问题讨论】:

【参考方案1】:

在 Core Data 中,您将使用 NSExpression 来获取最小值,并且 fetch 将以字典形式返回结果。所以,设置会有点不同。

您可以执行获取以获取每个最小值,执行如下操作:

NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:@"Fruit" inManagedObjectContext:myContext];
request.predicate = [NSPredicate predicateWithFormat:@"type = %@", @"banana"];

request.resultType = NSDictionaryResultType;

NSExpressionDescription *minExDescr = [[NSExpressionDescription alloc] init];
[minExDescr setName:@"myMinimum"];
[minExDescr setExpression:[NSExpression expressionForFunction:@"min:" 
                                                    arguments:[NSArray arrayWithObject:
                                                               [NSExpression expressionForKeyPath:@"price"]]]];
[minExDescr setExpressionResultType:NSFloatAttributeType];

request.propertiesToFetch = [NSArray arrayWithObject:minExDescr];

NSError *err = nil;
NSArray *bananaResults = [self.moContext executeFetchRequest:request error:&err];

由于 fetch 的结果是一个字典,您可以按如下方式检索最小值:

NSDictionary *resultsDictionary = [bananaResults lastObject];
NSNumber *bananaMinimum = [resultsDictionary objectForKey:@"myMinimum"]; 

请注意,这只会为您提供最小值,而不是您要求的行(或托管对象)。然后,您可以通过使用复合谓词的第二次提取来获取具有最小值的托管对象,以匹配类型和价格。 (我不知道在Core Data中是否可以直接一次获取托管对象。也许其他人可以发表评论。)

第二次提取的谓词如下:

NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:
                          [NSArray arrayWithObjects:
                           [NSPredicate predicateWithFormat:@"type = %@", @"banana"],
                           [NSPredicate predicateWithFormat:@"price = %@", bananaMinimum],
                           nil]];

所有这些都假设您提前知道类型。如果你不这样做(即如果它们正在改变),你可以使用setReturnsDistinctResults 初步获取所有不同的类型。您将不得不再次将setResultType 发送到NSDictionaryResultType。此外,setPropertiesToFetch 到包含您的类型属性的数组,以获取所有不同的类型。 只需按照setDistinctResults 的文档以及与上述相同的逻辑来设置提取。

此代码均未经过测试,因此可能存在拼写错误。

【讨论】:

以上是关于NSPredicate Core Data iOS 中的子查询的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 NSPredicate 过滤 Core Data 托管对象?

Core Data NSPredicate 过滤结果

使用 NSPredicate 从 Core Data 访问对象

使用 NSPredicate 遍历多个 Core Data 对象

iPhone如何使用NSPredicate按父实体过滤Core Data?

Core Data 中一对多关系的正确 NSPredicate 格式