找到最大(最后?)日期的SUBQUERY问题

时间:2011-06-30 03:55:19

标签: objective-c core-data nspredicate

我有两个实体'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..."

我不熟悉核心数据。有些帖子(onetwothree)很有趣,但对我来说还不够。我找不到关于SUBQUERY语法的详细信息。

1。你能解释一下如何在我的情况下用子查询得到正确的谓词吗?
2.您建议阅读有关子查询的内容(Predicate编程指南除外)

希望,这个问题对每个人都很有意思 期待您的建议 NIK

2 个答案:

答案 0 :(得分:3)

谓词格式字符串有几个问题:

SUBQUERY (Times, $s, max($s.timeDownload))
  1. SUBQUERY返回一个集合(即数组)。谓词需要评估为YESNO的表达式,而不是数组。数组不是布尔值。通常,您会看到SUBQUERY(...).@count > 0更多内容,意思是“执行此子查询,然后返回YES,如果它返回任何对象”。这可能适合你的情况,虽然我不太确定;我只是在评估格式字符串的语法正确性。

  2. SUBQUERY的第三个参数本身必须是谓词表达式。它必须评估为YESNOmax(oneThing)未评估为YESNO;它评估为oneThing

  3. 假设你得到了所有这些,我不确定核心数据是否可以将其识别为获取请求的谓词。 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)。

让我们对您的要求做出以下假设。

  • 您正在从服务器下载同一文件名的多个版本。
  • 每个文件都存储在Core Data外部,您只需要将文件名,文件路径放在磁盘上,下载时间放在Core Data本身。

然后,您可以将数据模型简化为:

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实体允许您按名称位置和下载时间的关键事件建模/模拟一个真实文件。

因为实体非常接近现实模型,这使得获取实际实体实例变得更加容易。

相关问题