我有两个实体'Times
'< * - > 'FileList
'。 “FileList
” - 具有“whenDownload
”关系,“Times
”的反向关系为“wichFile
”。
“FileList
”中的每个文件都可以多次下载,myApp会在文件系统中存储多个版本的文件。 'Times
'帮助我找到有关文件的准确版本和其他信息(评论等)
所以我有来自'FileList'的几个对象的filesArray并尝试从数组中找到每个FileList对象的最后下载版本,以了解是否有必要下载新版本。服务器端的文件不是我的。
我的代码:
NSFetchRequest *cutRequest = [[NSFetchRequest alloc] init];
cutRequest.entity = [NSEntityDescription entityForName:@"Times" inManagedObjectContext:localContext];
(NSArray *) listFilesToDownload = [self getListFilesToDownload]; // array with 30-90 files from 10k
NSPredicate * filePredicate = [NSPredicate predicateWithFormat:@"whichFile IN %@", listFilesToDownload];
// doesn't work:
//NSPredicate * timePredicate = [NSPredicate predicateWithFormat : @ "SUBQUERY(Times, $s, max($s.timeDownload))"];
//NSPredicate * timePredicate = [NSPredicate predicateWithFormat : @ "max (Times, $s, $s.timeDownload)"];
//NSPredicate * timePredicate = [NSPredicate predicateWithFormat : @ "(SUBQUERY (Times, $s, $s.timeDownload).max != 0)"];
//NSPredicate * timePredicate = [NSPredicate predicateWithFormat : @ "max (timeDownload)"];
//NSPredicate * timePredicate = [NSPredicate predicateWithFormat : @ "max (Times.timeDownload)"];
//NSString *name1 = @"timeDownload";
//NSPredicate * timePredicate = [NSPredicate predicateWithFormat : @ "max (%K)", name1];
NSPredicate * timePredicate = [NSPredicate predicateWithFormat : @ "SUBQUERY (Times, $time, max($time.timeDownload)).@count > 0"];
NSArray *allPredicates = [NSArray arrayWithObjects: filePredicate, timePredicate, nil];
cutRequest.predicate = [NSCompoundPredicate andPredicateWithSubpredicates:allPredicates];
cutRequest.fetchBatchSize = 300;
NSArray *arrayRequest = [localContext executeFetchRequest:cutRequest error:&error];
[cutRequest release];
我也试过单谓词:
NSPredicate * timePredicate = [NSPredicate predicateWithFormat : @ "(whichFile IN %@) AND (SUBQUERY (Times, $s, max($s.timeDownload))"];
但仍有"Unable to parse the format string..."
我不熟悉核心数据。有些帖子(one,two和three)很有趣,但对我来说还不够。我找不到关于SUBQUERY语法的详细信息。
1。你能解释一下如何在我的情况下用子查询得到正确的谓词吗?
2.您建议阅读有关子查询的内容(Predicate编程指南除外)
希望,这个问题对每个人都很有意思 期待您的建议 NIK
答案 0 :(得分:3)
谓词格式字符串有几个问题:
SUBQUERY (Times, $s, max($s.timeDownload))
SUBQUERY
返回一个集合(即数组)。谓词需要评估为YES
或NO
的表达式,而不是数组。数组不是布尔值。通常,您会看到SUBQUERY(...).@count > 0
更多内容,意思是“执行此子查询,然后返回YES
,如果它返回任何对象”。这可能适合你的情况,虽然我不太确定;我只是在评估格式字符串的语法正确性。
SUBQUERY
的第三个参数本身必须是谓词表达式。它必须评估为YES
或NO
。 max(oneThing)
未评估为YES
或NO
;它评估为oneThing
。
假设你得到了所有这些,我不确定核心数据是否可以将其识别为获取请求的谓词。 Core Data对谓词中可以执行的操作有一些非常严格的要求。此外,我非常确定SUBQUERY
符合“聚合表达式”,而核心数据不支持。
我说大约99%的时间你认为你需要使用SUBQUERY
,你不这样做,而你实际上不应该这样做。它很少有用,而且它的使用非常奇怪,它通常会使你的谓词难以理解,从而在将来不易维护。
简而言之:找到一种不同的方式来做到这一点。你有一个文件列表,你想获得与上次下载时对应的Times
对象,对吧?我认为这就是这样的:
NSPredicate *p = [NSPredicate predicateWithFormat:@"whichFile.name IN %@ AND timeDownload = whichFile.whenDownload.@max.timeDownload", listFilesToDownload];
这假定listFilesToDownload
是一个文件名数组,并且您的FileList
实体具有name
属性,该属性是文件名,并且与列表中的一个匹配...
(我认为)你感兴趣的是这个:
timeDownload = whichFile.whenDownload.@max.timeDownload
如果此文件的下载时间等于此时间YES
的所有时间的最大下载时间,则评估为FileList
。或类似的东西。你的命名非常糟糕(可以原谅,因为看起来英语不是你的母语),这肯定会妨碍我的解释,但你去了。
享受。
答案 1 :(得分:0)
根据经验,当您发现自己必须在谓词中使用子查询时,这通常表明您遇到了设计问题。它通常意味着(1)你对错误的实体的提取或(2)你的数据模型不是最理想的。
在这种情况下,我认为是(2)。
让我们对您的要求做出以下假设。
然后,您可以将数据模型简化为:
DownFile{
name:string
path:string
downloadTime:date
}
每个DownFile
实例都存储单个下载文件的信息。您可能有许多具有相同名称(或ID号或其他标识符)的文件,但文件名的每个版本在磁盘上都有唯一的路径和唯一的下载时间戳。
要查找具有特定名称的文件的上次下载版本,您可以仅使用谓词作为名称。
NSPredicate *p=[NSPredicate predicateWithFormat:@"name == %@", soughtName];
然后你可以提供一个排序描述符,按日期排序,将最新日期放在最上面:
NSSortDescriptor * sort = [NSSortDescriptor sortDescriptorWithKey:@“downloadTime”升序:否];
当您使用上述谓词和排序运行fetch时,它将返回一个数组,其中包含与DownFile
变量同名的所有soughtName
实例,所有这些实例都按降序日期排序。要查找上次下载的版本,只需获取数组的零元素。
除了更简单之外,这种设计比针对大量对象运行子查询更快。
即使这个特定的模型不适合你,它也应该为你提供一个起点。核心数据旨在模拟/模拟真实世界的对象,条件或事件以及它们之间的关系。因此,您的模型应该反映出真正的模型。在这种情况下,你有
downloaded files -->> Object
download time -->> Event
由于每个文件的下载时间都是唯一的,因此您需要将其作为模拟文件的实体的主要属性。 (请注意,实体模拟真实世界对象,条件或事件的单个实例。)DownFile
实体允许您按名称位置和下载时间的关键事件建模/模拟一个真实文件。
因为实体非常接近现实模型,这使得获取实际实体实例变得更加容易。