SUBQUERY 查找最大(最后一个?)日期时出现问题

发布于 2024-11-18 07:53:29 字数 2757 浏览 1 评论 0 原文

我有两个实体 'Times' <*-> '文件列表'。 'FileList' - 具有关系 'whenDownload','Times' 的反向关系是 'wichFile'。 “FileList”中的每个文件都可以被下载多次,并且 myApp 在文件系统中存储多个版本的文件。 “Times”帮助我找到有关文件的确切版本和其他信息(评论等)。
因此,我有 filesArray 和“FileList”中的多个对象,并尝试从数组中查找每个 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))"];

但仍然有 “无法解析格式字符串...”

我不熟悉核心数据。一些帖子(一个两个三个 )很有趣,但对我来说还不够。我找不到有关带有函数的 SUBQUERY 语法的足够详细信息。

1.您能否解释一下在我的情况下如何使用子查询获得正确的谓词?
2. 关于子查询,您推荐阅读哪些内容(除了谓词编程指南:)

希望,这个问题对每个人来说都会感兴趣。
期待您的建议。
尼克

I have two entities 'Times' <*-> 'FileList'. 'FileList' - has relation 'whenDownload', reverse relation from 'Times' is 'wichFile'.
Every file in 'FileList' could be download several times and myApp stores several versions of files in file system. 'Times' helps me to find exact version and other information about file (comments, etc).
So I have filesArray with several objects from 'FileList' and try to find last download version each FileList objects from array to understand is it necessary to download new versions or not. Server-side with files is not mine.
My code:

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];

also I tried single predicate:

 NSPredicate * timePredicate =  [NSPredicate predicateWithFormat : @ "(whichFile IN %@) AND (SUBQUERY (Times, $s, max($s.timeDownload))"];

but still have "Unable to parse the format string..."

I'm not familiar with Core Data. Some posts (one, two and three) were interesting, but not enough for me. I couldn't find enough details about SUBQUERY syntax with functions.

1. Could you explane how to get correct predicate with subquery in my case ?
2. What are you recommend to read about subquery (except Predicate programming guide :)

Hope, the question would be interesting for everybody.
Looking forward for your advices.
Nik

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

故人的歌 2024-11-25 07:53:29

您的谓词格式字符串存在一些问题:

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

  2. SUBQUERY 的第三个参数本身必须是谓词表达式。它的计算结果必须为 YESNOmax(oneThing) 的计算结果不会为 YESNO;它的计算结果为oneThing

假设您所有这些都正确,我不确定它是否会被核心数据识别为获取请求的谓词。核心数据对于您可以在谓词中执行哪些操作有一些非常严格的要求。此外,我非常确定 SUBQUERY 符合“聚合表达式”的资格,而 Core Data 不支持该表达式。

我想说,大约 99% 的情况下,您认为需要使用 SUBQUERY,但实际上不需要,而且实际上也不应该。它很少有用,而且它的使用非常奇怪,通常会使你的谓词更难理解,从而在将来更难维护。

简而言之:找到一种不同的方法来做到这一点。您有一个文件列表,并且您想要获取与上次下载时间相对应的 Times 对象,对吧?我认为事情是这样的:

NSPredicate *p = [NSPredicate predicateWithFormat:@"whichFile.name IN %@ AND timeDownload = [email protected]", listFilesToDownload];

这假设 listFilesToDownload 是一个文件名数组,并且您的 FileList 实体有一个 name属性是文件的名称并与列表中的一个匹配...

(我认为)您感兴趣的一点是:

timeDownload = [email protected]

如果此文件的下载时间,这将评估为 YES等于所有Times的最大下载时间这次的FileList。或者类似的东西。你的命名非常糟糕(可以原谅,因为英语似乎不是你的母语),这肯定妨碍了我的解释,但就这样吧。

享受。

There are a couple things wrong with your predicate format string:

SUBQUERY (Times, $s, max($s.timeDownload))
  1. SUBQUERY returns a collection (ie, an array). Predicates want expressions that evaluate to YES or NO, not to an array. An array is not a boolean value. Typically you see something more along the lines of SUBQUERY(...).@count > 0, meaning "perform this subquery, and then return YES if it returned any objects". This may be appropriate in your case, though I'm not really sure; I'm just evaluating the syntactic correctness of your format string.

  2. The third parameter to a SUBQUERY must itself be a predicate expression. It must evaluate to YES or NO. max(oneThing) does not evaluate to YES or NO; it evaluates to oneThing.

Assuming you get all of this correct, I'm not sure it's even going to be recognizable by Core Data as the predicate to a fetch request. Core Data has some pretty stringent requirements on what sorts of things you can do in a predicate. Additionally, I'm pretty sure that SUBQUERY qualifies as an "aggregate expression", which Core Data does not support.

I'd say that about 99% of the time you think you need to use a SUBQUERY, you don't, and you actually shouldn't. It's very rarely useful, and its use is bizarre enough that it generally makes your predicate harder to understand, and thus less maintainable in the future.

In a nutshell: find a different way to do this. You have a list of files, and you want to get the Times object corresponding to the last time it was downloaded, right? I think that'd be something like this:

NSPredicate *p = [NSPredicate predicateWithFormat:@"whichFile.name IN %@ AND timeDownload = [email protected]", listFilesToDownload];

This assumes that listFilesToDownload is an array of file names, and that your FileList entity has a name property that's the name of the file and matches one in the list...

The bit that (I think) you're interested in is this:

timeDownload = [email protected]

This will evaluate to YES if the download time of this file is equal to the maximum download time of all of the Times of this Time's FileList. Or something like that. Your naming is pretty terrible (excusable, since it doesn't appear that English is your native language), and that's definitely hindering my explanation, but there you go.

Enjoy.

丑疤怪 2024-11-25 07:53:29

根据经验,当您发现自己必须在谓词中使用子查询时,这通常表明您遇到了设计问题。这通常意味着(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" ascending:NO];

当您使用上述谓词运行 fetch 并进行排序时,它将返回一个由 DownFile 的所有实例组成的数组,这些实例与 soughtName 变量具有相同的名称,并且全部按降序日期排序。要查找最后下载的版本,只需获取数组的零元素即可。

除了更简单之外,这种设计比针对大量对象运行子查询要快得多。

即使这个特定模型不适合您,它也应该为您提供一个起点。核心数据旨在建模/模拟现实世界的对象、条件或事件以及它们之间的关系。因此,您的模型应该反映实际情况。在这种情况下,

downloaded files -->> Object
download time -->> Event

由于每个文件仅在下载时间方面是唯一的,因此您需要将其作为对文件进行建模的实体的主要属性。 (请注意,实体对真实世界对象、条件或事件的单个实例进行建模。)DownFile 实体可让您根据名称位置及其关键事件来建模/模拟一个真实世界文件。下载时间。

由于实体紧密模拟现实,因此获取实际实体实例变得非常非常容易。

As a rule of thumb, when you find yourself having to use a subquery in a predicate that is often a sign that you've got a design problem. It usually means that (1) your fetching against the wrong entity or (2) that you data model is suboptimal.

In this case, I think it is (2).

Let's make the following assumptions about your requirements.

  • You are downloading multiple versions of same filename from a server.
  • Each file is stored external to Core Data and that you only need to put the filename, path to the file on disk and the download time in Core Data itself.

You can then simplify your data model to just:

DownFile{
  name:string
  path:string
  downloadTime:date
}

Each DownFile instance stores the information for a single downloaded file. You may have many files with the same name (or id number or other identifier) but each version of the filename will have a unique path on disk and a unique download timestamp.

To find the last download version of a file with a particular name, you would use a predicate for just the name.

NSPredicate *p=[NSPredicate predicateWithFormat:@"name == %@", soughtName];

Then you can provide a sort descriptor which sorts by date putting the latest date at the top:

NSSortDescriptor *sort=[NSSortDescriptor sortDescriptorWithKey:@"downloadTime" ascending:NO];

When you run a fetch with the above predicate and sort, it will return an array of all instances of DownFile that have the same name as the soughtName variable all sorted by descending date. To find the last downloaded version just get the zero element of the array.

Besides being more simple, this design is way faster than running subqueries against a vast number of objects.

Even if this particular model won't work for you, it should provide you a starting point. Core Data is intended to model/simulate real-world objects, conditions or events and the relationships between them. Therefore your model should reflect what is really going one. In this case, you have

downloaded files -->> Object
download time -->> Event

Since each file is unique only by its download time, you need to make that the major attribute of the entity that models the files. (Note that an entity models a single instances of a real-world object, condition or event.) The DownFile entity lets you model/simulate one real-world file by name location and the critical event of its time of download.

Because the entity closely models reality, that makes fetching the actual entity instances much, much easier.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文