【问题标题】:NSPredicate returns different results on a fecthRequest vs filtering an arrayNSPredicate 在 fecthRequest 与过滤数组时返回不同的结果
【发布时间】:2013-02-10 13:10:34
【问题描述】:

我有一个 Core Data SQLite 类型存储,我的实体中名为 Article 的属性之一是一个名为 markAsArchived 的字符串属性。

我想做的是设置一个获取请求来获取前 100 个 markAsArchived 不是 YES(字符串值,而不是 bool)的项目。

所以,这是我用来设置获取请求的代码,它返回 0 个结果。

NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Article"];
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"date" ascending:NO]];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"markAsArchived != 'YES'"]];
[fetchRequest setFetchLimit:100];
NSError *error = nil;
self.articles = [NSMutableArray arrayWithArray:[self.managedObjectContext executeFetchRequest:fetchRequest error:&error]];

if (error) {
    //Handle the error
    NSLog(@"%@", error);
}

但是,如果我采用完全相同的谓词,将其从 fetch 请求中删除,而是使用它来过滤 fetch 请求返回的数组,我会得到一些想要的结果。这是我用来执行此操作的代码。

NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Article"];
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"date" ascending:NO]];
[fetchRequest setFetchLimit:100];
NSError *error = nil;
self.articles = [NSMutableArray arrayWithArray:[self.managedObjectContext executeFetchRequest:fetchRequest error:&error]];

if (error) {
    //Handle the error
    NSLog(@"%@", error);
}
self.articles = [NSMutableArray arrayWithArray:[self.articles filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"markAsArchived != 'YES'"]]];

现在,我的问题是,由于我正在过滤包含 100 个获取项目的数组,因此过滤后的结果通常最终小于 100,这不是我想要的。

我的猜测是,在使用谓词设置获取请求时,我正在做一些令人难以置信的事情。关于我可能做错了什么的任何指示?

PS: 将 markAsArchived 更改为 bool 属性而不是 string 属性不是一种选择。

更新:我查看了以下问题,但似乎没有一个对我有帮助。

NSPredicate Returns No Results with Fetch Request, Works with Array Filtering

Predicate works for array but not for fetchRequest

更新(2013 年 3 月 1 日):* 据我所知,executeFetchRequest 返回一个空数组,而不是 nil。我仔细检查以确定。

这是我使用启动参数得到的调试输出...

2013-03-01 20:29:48.218 PROJECTNAME[753:907] CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZCONTENT, t0.ZDATE, t0.ZENCLOSURELENGHT, t0.ZENCLOSURETYPE, t0.ZENCLOSUREURL, t0.ZFULLTEXT, t0.ZIDENTIFIER, t0.ZIMAGE, t0.ZLINK, t0.ZMARKASARCHIVED, t0.ZREAD, t0.ZREADPOSITION, t0.ZSUMMARY, t0.ZTITLE, t0.ZUPDATED, t0.ZFEED FROM ZARTICLE t0 WHERE  t0.ZMARKASARCHIVED <> ? ORDER BY t0.ZDATE DESC LIMIT 119
2013-03-01 20:29:48.221 PROJECTNAME[753:907] CoreData: details: SQLite bind[0] = "YES"
2013-03-01 20:29:48.287 PROJECTNAME[753:907] CoreData: annotation: sql connection fetch time: 0.0689s
2013-03-01 20:29:48.289 PROJECTNAME[753:907] CoreData: annotation: fetch using NSSQLiteStatement <0x1f218d70> on entity 'Article' with sql text 'SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZCONTENT, t0.ZDATE, t0.ZENCLOSURELENGHT, t0.ZENCLOSURETYPE, t0.ZENCLOSUREURL, t0.ZFULLTEXT, t0.ZIDENTIFIER, t0.ZIMAGE, t0.ZLINK, t0.ZMARKASARCHIVED, t0.ZREAD, t0.ZREADPOSITION, t0.ZSUMMARY, t0.ZTITLE, t0.ZUPDATED, t0.ZFEED FROM ZARTICLE t0 WHERE  t0.ZMARKASARCHIVED <> ? ORDER BY t0.ZDATE DESC LIMIT 119' returned 0 rows with values: ( )
2013-03-01 20:29:48.291 PROJECTNAME[753:907] CoreData: annotation: total fetch execution time: 0.0734s for 0 rows.

【问题讨论】:

  • 我假设您已经完成了显而易见的操作:仔细检查所有属性名称(大写/小写)并重新生成 NSManagedObject 子类?
  • @MartinR:肯定的。事实上,这就是我几天来一直在做的所有事情。 :-(
  • 你能检查[self.managedObjectContext executeFetchRequest:fetchRequest error:&amp;error]的返回值吗? executeFetchRequest 是返回一个空数组还是 nil? (arrayWithArray 在这两种情况下都会返回一个空数组,所以你必须检查实际的返回值!)
  • 另一个建议:设置启动参数-com.apple.CoreData.SQLDebug = 3 并向我们展示为executeFetch 调用创建的调试输出。
  • 你在这个奇怪的问题上取得了进展吗?

标签: ios cocoa-touch sqlite core-data nspredicate


【解决方案1】:

假设您需要属性markedAsArchived 是一个字符串(您会同意这是糟糕的设计),那么获取请求的正确谓词是:

[NSPredicate predicateWithFormat:@"markedAsArchived != %@", @"YES"]

在谓词格式字符串中将常量替换为文字是不安全的。以上是检查此属性的标准方法。

【讨论】:

  • 我在这里使用其他人的代码,并且同意,设计非常粗糙。 markedAsArchived 可以不仅仅是 YES 或 NO。不幸的是,!= 或 谓词似乎根本不起作用。我已经尝试使用您在此处提供的格式以及其他一些格式设置谓词。唯一似乎获得预期结果的事情是设置一个包含一大堆 == 谓词的复合谓词,以寻找除 YES 之外的所有其他可能性。
  • @SamJ.:所以“==”可以正常工作,但“!=”不能? "NOT (markedAsArchived == 'YES')" 呢?
  • @MartinR :是的,“==”工作正常,但“!=”和“”不能。而且,不,“NOT (markAsArchived == 'YES')”似乎也不起作用。关于核心数据我还有很多东西要学,所以我想我也应该问一下,除了所有不同的可能性之外,markAsArchived 也可以为零有关系吗?
  • 你也可以用 predicateWithFormat:@"attr = NIL"]; 与 nil 进行比较。此外,如果您正在使用其他人的代码,则没有理由不进行重构。
  • @Mundi :是的,这是我的复合谓词的一部分。而且,是的,重构可能是我最好的选择。但是,这个问题的重点是弄清楚这是否可以使用简单的谓词,以及为什么!= 谓词不起作用而== 谓词起作用。试图找出问题的原因,而不是试图完全回避它。告诉我这是糟糕的设计并且我应该重构(我同意这两者。)并没有做到这一点。
【解决方案2】:

我偶然发现了同样的问题......在我的例子中,它与构建谓词字符串有关。如果你使用引号,你需要小心。在你的代码中我看到:

[NSPredicate predicateWithFormat:@"markAsArchived != 'YES'"];

但实际上可能需要:

[NSPredicate predicateWithFormat:@"markAsArchived != YES"];

我遇到同样的问题是 NSNumber 被引号括起来。

哈利

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-07-21
    • 2020-02-29
    • 2018-09-02
    • 1970-01-01
    • 1970-01-01
    • 2020-12-29
    • 1970-01-01
    相关资源
    最近更新 更多