CoreData:相同的谓词(IN)在保存操作后返回不同的获取结果

     2023-03-05     269

关键词:

【中文标题】CoreData:相同的谓词(IN)在保存操作后返回不同的获取结果【英文标题】:CoreData: Same predicate (IN) returns different fetched results after a Save operation 【发布时间】:2014-06-06 15:28:00 【问题描述】:

重大更新:

我创建了一个全新的项目来模拟这个问题,它确实一直出现!

这是我的数据模型:

Task 具有指向Person 的一对多关系。

@interface Person : NSManagedObject

@property (nonatomic, retain) NSString * personId;
@property (nonatomic, retain) NSString * name;

@end

//

@class Person;

@interface Task : NSManagedObject

@property (nonatomic, retain) NSNumber * taskId;
@property (nonatomic, retain) NSSet *watchers;
@end

@interface Task (CoreDataGeneratedAccessors)

- (void)addWatchersObject:(Person *)value;
- (void)removeWatchersObject:(Person *)value;
- (void)addWatchers:(NSSet *)values;
- (void)removeWatchers:(NSSet *)values;

@end

现在,我创建两个人,p1 和 p2,以及两个任务,1001 和 1002:

- (void)viewDidLoad

    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    Person *p1 = [self insertOrUpdatePerson:@"111" withName:@"aaa"];
    Person *p2 = [self insertOrUpdatePerson:@"222" withName:@"bbb"];

    [self insertOrUpdateTask:1001 withWatcher:p1];
    [self insertOrUpdateTask:1001 withWatcher:p2];

    [self insertOrUpdateTask:1002 withWatcher:p1];
    [self insertOrUpdateTask:1002 withWatcher:p2];

    NSArray *watchedTasks = nil;

    watchedTasks = [self fetchTasksWatchedByPerson:p1]; // return 2 objects
    NSLog(@"watchedTasks : %@\n", watchedTasks);
    [self saveContext];
    watchedTasks = [self fetchTasksWatchedByPerson:p1]; // return 1 objects
    NSLog(@"watchedTasks : %@\n", watchedTasks);

    NSArray *allTasks = [self fetchAllTasks]; // return 2 objects
    NSLog(@"allTasks : %@\n", watchedTasks);

日志如下。 注意,watchedTasks 的第二个输出只有一个对象!

Printing description of watchedTasks:
<__NSArrayI 0x8d5aff0>(
<Task: 0x8d5b240> (entity: Task; id: 0x8d5b3e0 <x-coredata://706EB8CA-ACE7-48DB-89E1-7CCFCDD41DA4/Task/p2> ; data: 
    taskId = 1002;
    watchers =     (
        "0x8d57f80 <x-coredata://706EB8CA-ACE7-48DB-89E1-7CCFCDD41DA4/Person/p2>",
        "0x8d56070 <x-coredata://706EB8CA-ACE7-48DB-89E1-7CCFCDD41DA4/Person/p1>"
    );
),
<Task: 0x8d59d10> (entity: Task; id: 0x8d59420 <x-coredata://706EB8CA-ACE7-48DB-89E1-7CCFCDD41DA4/Task/p1> ; data: 
    taskId = 1001;
    watchers =     (
        "0x8d57f80 <x-coredata://706EB8CA-ACE7-48DB-89E1-7CCFCDD41DA4/Person/p2>",
        "0x8d56070 <x-coredata://706EB8CA-ACE7-48DB-89E1-7CCFCDD41DA4/Person/p1>"
    );
)
)

Printing description of updateObjects:
<__NSArrayI 0x8e41880>(
<Task: 0x8d59d10> (entity: Task; id: 0x8d59420 <x-coredata://706EB8CA-ACE7-48DB-89E1-7CCFCDD41DA4/Task/p1> ; data: 
    taskId = 1001;
    watchers =     (
        "0x8d57f80 <x-coredata://706EB8CA-ACE7-48DB-89E1-7CCFCDD41DA4/Person/p2>",
        "0x8d56070 <x-coredata://706EB8CA-ACE7-48DB-89E1-7CCFCDD41DA4/Person/p1>"
    );
),
<Task: 0x8d5b240> (entity: Task; id: 0x8d5b3e0 <x-coredata://706EB8CA-ACE7-48DB-89E1-7CCFCDD41DA4/Task/p2> ; data: 
    taskId = 1002;
    watchers =     (
        "0x8d57f80 <x-coredata://706EB8CA-ACE7-48DB-89E1-7CCFCDD41DA4/Person/p2>",
        "0x8d56070 <x-coredata://706EB8CA-ACE7-48DB-89E1-7CCFCDD41DA4/Person/p1>"
    );
),
<Person: 0x8d56cc0> (entity: Person; id: 0x8d56070 <x-coredata://706EB8CA-ACE7-48DB-89E1-7CCFCDD41DA4/Person/p1> ; data: 
    name = aaa;
    personId = 111;
),
<Person: 0x8d57be0> (entity: Person; id: 0x8d57f80 <x-coredata://706EB8CA-ACE7-48DB-89E1-7CCFCDD41DA4/Person/p2> ; data: 
    name = bbb;
    personId = 222;
)
)

Printing description of watchedTasks:
<_PFArray 0x8f57da0>(
<Task: 0x8d5b240> (entity: Task; id: 0x8d5b3e0 <x-coredata://706EB8CA-ACE7-48DB-89E1-7CCFCDD41DA4/Task/p2> ; data: 
    taskId = 1002;
    watchers =     (
        "0x8d57f80 <x-coredata://706EB8CA-ACE7-48DB-89E1-7CCFCDD41DA4/Person/p2>",
        "0x8d56070 <x-coredata://706EB8CA-ACE7-48DB-89E1-7CCFCDD41DA4/Person/p1>"
    );
)
)

Printing description of allTasks:
<_PFArray 0x8e44b30>(
<Task: 0x8d59d10> (entity: Task; id: 0x8d59420 <x-coredata://706EB8CA-ACE7-48DB-89E1-7CCFCDD41DA4/Task/p1> ; data: 
    taskId = 1001;
    watchers =     (
        "0x8d57f80 <x-coredata://706EB8CA-ACE7-48DB-89E1-7CCFCDD41DA4/Person/p2>",
        "0x8d56070 <x-coredata://706EB8CA-ACE7-48DB-89E1-7CCFCDD41DA4/Person/p1>"
    );
),
<Task: 0x8d5b240> (entity: Task; id: 0x8d5b3e0 <x-coredata://706EB8CA-ACE7-48DB-89E1-7CCFCDD41DA4/Task/p2> ; data: 
    taskId = 1002;
    watchers =     (
        "0x8d57f80 <x-coredata://706EB8CA-ACE7-48DB-89E1-7CCFCDD41DA4/Person/p2>",
        "0x8d56070 <x-coredata://706EB8CA-ACE7-48DB-89E1-7CCFCDD41DA4/Person/p1>"
    );
)
)
(lldb) 

所以我打开 .sqlite 文件看看里面到底有什么。

首先让我感到惊讶的是watchersPerson 表中,而不是在中间/映射Task2Person 表中。我记得一旦关系存在于中间表中。

那么,Person 表中的watchers 字段只包含一个值,而不是集合或数组!

- (void)viewDidLoad

    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    NSArray *watchedTasks = nil;

    Person *p1 = [self insertOrUpdatePerson:@"111" withName:@"aaa"];
    Person *p2 = [self insertOrUpdatePerson:@"222" withName:@"bbb"];

    watchedTasks = [self fetchTasksWatchedByPerson:p1]; // return 1 object

    Task *t1 = [self insertOrUpdateTask:1001 withWatcher:p1]; // update watchers in the memory
    [self insertOrUpdateTask:1001 withWatcher:p2];

    Task *t2 = [self insertOrUpdateTask:1002 withWatcher:p1];
    [self insertOrUpdateTask:1002 withWatcher:p2];

    watchedTasks = [self fetchTasksWatchedByPerson:p1]; // return 2 objects

    [self saveContext];

    watchedTasks = [self fetchTasksWatchedByPerson:p1]; // return 1 object

所以我发现在我启动应用程序并从 db 文件中读取任务后,只返回 1 个对象。

当我更新任务的watchers 信息时,可以获取 2 个对象。

最后在我保存上下文之后,又只有 1 个对象了。


忽略这个

- 下面的旧信息

我的代码如下:

        NSArray *existedTasks = [[TaskBizDB sharedInstance] fetchTasksWatchedByMeOfProject:projectId];
        [context save:&error];
        existedTasks = [[TaskBizDB sharedInstance] fetchTasksWatchedByMeOfProject:projectId];

        NSArray *allTasks = [[TaskBizDB sharedInstance] fetchTasksOfProject:projectId];
第一行返回两个对象; 第二行保存上下文; 第三行返回只有一个对象,包含在上面的“两个对象”中; 最后一行返回 6 个对象,包含“两个对象” 在第一行返回。

获取接口的工作原理如下:

WXModel *model = [WXModel modelWithEntity:NSStringFromClass([WQPKTeamTask class])];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(%@ IN personWatchers) AND (projectId == %d)", currentLoginUser, projectId];
[model setPredicate:predicate];
NSArray *fetchedTasks = [model fetch];
if (fetchedTasks.count == 0) return nil;

return fetchedTasks;

让我感到困惑的是,对于相同的 fetch 请求,为什么在保存后返回不同的结果?

这里有更多细节:

第一行返回的“两个对象”是:

<WQPKTeamTask: 0x1b92fcc0> (entity: WQPKTeamTask; id: 0x1b9300f0 <x-coredata://CFFD3F8B-E613-4DE8-85AA-4D6DD08E88C5/WQPKTeamTask/p9> ; data: 
    projectId = 372004;
    taskId = 338001;
    personWatchers =     (
        "0xf0bf440 <x-coredata://CFFD3F8B-E613-4DE8-85AA-4D6DD08E88C5/WWPerson/p1>"
    );


<WQPKTeamTask: 0xf3f6130> (entity: WQPKTeamTask; id: 0xf3cb8d0 <x-coredata://CFFD3F8B-E613-4DE8-85AA-4D6DD08E88C5/WQPKTeamTask/p11> ; data: 
    projectId = 372004;
    taskId = 340006;
    personWatchers =     (
        "0xf0bf440 <x-coredata://CFFD3F8B-E613-4DE8-85AA-4D6DD08E88C5/WWPerson/p1>"
    );

第三行返回的唯一一个对象是:

<WQPKTeamTask: 0x1b92fcc0> (entity: WQPKTeamTask; id: 0x1b9300f0 <x-coredata://CFFD3F8B-E613-4DE8-85AA-4D6DD08E88C5/WQPKTeamTask/p9> ; data: 
    projectId = 372004;
    taskId = 338001;
    personWatchers =     (
        "0xf0bf440 <x-coredata://CFFD3F8B-E613-4DE8-85AA-4D6DD08E88C5/WWPerson/p1>"
    );

allTask​​s的打印说明:

<_PFArray 0xf30b9a0>(
<WQPKTeamTask: 0xf3ab9d0> (entity: WQPKTeamTask; id: 0xf3cda40 <x-coredata://CFFD3F8B-E613-4DE8-85AA-4D6DD08E88C5/WQPKTeamTask/p6> ; data: <fault>),
<WQPKTeamTask: 0xf315720> (entity: WQPKTeamTask; id: 0xf3c23a0 <x-coredata://CFFD3F8B-E613-4DE8-85AA-4D6DD08E88C5/WQPKTeamTask/p7> ; data: <fault>),
<WQPKTeamTask: 0xf3a1ed0> (entity: WQPKTeamTask; id: 0xf3cda30 <x-coredata://CFFD3F8B-E613-4DE8-85AA-4D6DD08E88C5/WQPKTeamTask/p8> ; data: <fault>),
<WQPKTeamTask: 0x1b92fcc0> (entity: WQPKTeamTask; id: 0x1b9300f0 <x-coredata://CFFD3F8B-E613-4DE8-85AA-4D6DD08E88C5/WQPKTeamTask/p9> ; data: 
    projectId = 372004;
    taskId = 338001;
    personWatchers =     (
        "0xf0bf440 <x-coredata://CFFD3F8B-E613-4DE8-85AA-4D6DD08E88C5/WWPerson/p1>"
    );
),
<WQPKTeamTask: 0xf325e50> (entity: WQPKTeamTask; id: 0xf343820 <x-coredata://CFFD3F8B-E613-4DE8-85AA-4D6DD08E88C5/WQPKTeamTask/p10> ; data: <fault>),
<WQPKTeamTask: 0xf3f6130> (entity: WQPKTeamTask; id: 0xf3cb8d0 <x-coredata://CFFD3F8B-E613-4DE8-85AA-4D6DD08E88C5/WQPKTeamTask/p11> ; data: 
    projectId = 372004;
    taskId = 340006;
    personWatchers =     (
        "0xf0bf440 <x-coredata://CFFD3F8B-E613-4DE8-85AA-4D6DD08E88C5/WWPerson/p1>"
    );
)
)

更新 1

如果我调用同一个接口fetchTasksWatchedByMeOfProject: in:

#pragma mark - NSFetchedResultsController Delegate

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller

我也会得到“两个对象”。

更新 2

我试过了:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(ANY personWatchers == %@) AND (projectId == %d)", currentLoginUser, projectId];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(ANY personWatchers.personId == %@) AND (projectId == %d)", currentLoginUserId, projectId];

还是一样的结果。

更新 3

我检查了save:&amp;error,错误为零。

【问题讨论】:

你看到save:的返回值是什么,错误是否还是nil? (我不明白这有什么关系,但是 save 有两种方法可以报告问题,而且您都没有检查,至少在此处的代码中。) @stevesliva 感谢您的提示。我检查了save:,错误为零。 明确一点,如果返回是YES,您应该只查看结果然后对错误做出反应。仅查看错误是不够的和/或具有误导性。 【参考方案1】:

保存了什么?

在保存之前打印出-[NSManagedObjectContext updatedObjects] 会发生什么?

最终谓词是什么样的?你能打印出NSFetchRequest的描述吗?

【讨论】:

感谢提示 :) 我创建了一个新项目来定位问题,并在 .sqlite 文件中发现了一些变化。【参考方案2】:

我今天和我的队友一起解决了这个问题。

如果您创建一个没有反向关系的一对多关系,例如,Taskwatchers 具有一对多关系 Person,但 PersonTask 没有反向关系, 那么关系字段watchers 将被放入Person 表而不是中间/映射表中。

在这种情况下,我在Task t1 的watchers 中添加一个Person p1 会将Person 表中的watchers 字段更新为1

然后,将Person p1 也添加到Task t2 中,watchers 字段将更新为2,如下所示:

所以,一个Person 只能指向一个Task

通过添加从PersonTask 的反向关系可以绕过这个问题。

【讨论】:

CoreData:使用 IN 基于谓词/数组进行排序

】CoreData:使用IN基于谓词/数组进行排序【英文标题】:CoreData:sortbasedonpredicate/arrayusingIN【发布时间】:2012-01-1321:07:34【问题描述】:我有一个CoreData存储,并希望维护REST服务提供的排序顺序。CoreData中的对象具有guid属性,并且... 查看详情

Coredata fetchrequest 谓词没有显示正确的东西

】Coredatafetchrequest谓词没有显示正确的东西【英文标题】:Coredatafetchrequestpredicatedoesn\'tshowtherightthings【发布时间】:2016-04-2212:25:39【问题描述】:我是swift新手,我尝试使用CoreData制作应用程序,但谓词没有显示正确的结果。似... 查看详情

在谓词中评估 CoreData 实体类型

】在谓词中评估CoreData实体类型【英文标题】:EvaluateCoreDataentitytypeinpredicate【发布时间】:2013-05-0314:48:45【问题描述】:我有一个我精心设计的块谓词,只是发现你不能在CoreData中使用它们。NSPredicate*rootContactPredicate=[NSPredicatepred... 查看详情

带有函数参数的 CoreData 谓词

】带有函数参数的CoreData谓词【英文标题】:CoreDataPredicatewithFunctionArgument【发布时间】:2019-04-0204:36:21【问题描述】:我试图在谓词定义中包含一个函数。这可能吗?假设您有一个Places的核心数据实体,其属性为纬度和经度。我... 查看详情

一对多关系的CoreData谓词

】一对多关系的CoreData谓词【英文标题】:CoreDatapredicateforonetomanyrelationship【发布时间】:2014-09-1909:04:38【问题描述】:我有两个实体:A和B。A的每个元素都可以有更多的B元素(一对多)。现在我有一个项目A,我想在这个项目中... 查看详情

如何在 coredata 中设置日期和时间间隔的谓词

】如何在coredata中设置日期和时间间隔的谓词【英文标题】:HowtosetthePredicatefordateandtimeintervalincoredata【发布时间】:2014-05-2112:21:03【问题描述】:我正在使用情节提要和核心数据开发一个iPad应用程序。在我的核心数据中,我有... 查看详情

在 CoreData 中保存操作值导致错误

】在CoreData中保存操作值导致错误【英文标题】:savingmanipulatedvaluesinCoreDatacausingerror【发布时间】:2018-04-0704:31:23【问题描述】:我在core-data中有一个名为Record的实体。问题是我在操作后无法保存对象,如下所示:extensionRecords@no... 查看详情

具有长长值的 CoreData 的 iOS 谓词不够精确

】具有长长值的CoreData的iOS谓词不够精确【英文标题】:iOSPredicateforCoreDatawithlonglongvalueswerenotpreciseenough【发布时间】:2015-02-1008:30:10【问题描述】:我一直在构建的这个应用程序在iPad上运行,我一直在使用XCode6.1.1在iOS8.1上对其... 查看详情

CoreData 在后台 MOC 的保存操作期间无法完成故障

】CoreData在后台MOC的保存操作期间无法完成故障【英文标题】:CoreDatacan\'tfulfillafaultduringsaveoperationfrombackgroundMOC【发布时间】:2014-12-3109:29:10【问题描述】:我正在使用两个MOC,一个用于主线程,另一个MOC用于后台线程。在主线... 查看详情

CoreData 的自定义 UID 数据类型

】CoreData的自定义UID数据类型【英文标题】:CustomUIDdatatypeforCoreData【发布时间】:2009-08-2822:04:09【问题描述】:CoreData文档说“您有时可以从创建自己的唯一ID(UUID)属性中受益,该属性可以为新插入的对象定义和设置。这允许您... 查看详情

CoreData 的谓词查询

】CoreData的谓词查询【英文标题】:PredicateQueryforCoreData【发布时间】:2014-03-1020:01:51【问题描述】:我想编写一个使用NSPredicate的搜索函数来搜索元素的开头[不包含,我目前拥有但开始]。现在我的谓词是:NSPredicate*resultPredicate=[... 查看详情

Swift coreData - 格式化日期并在谓词中使用它

】SwiftcoreData-格式化日期并在谓词中使用它【英文标题】:SwiftcoreData-formatdateanduseitinpredicate【发布时间】:2017-09-1410:57:49【问题描述】:H.我有一个名为Agendadate的实体和一个名为AgendaEvent的实体。AgendaEvent与AgendaDate(agendaDates)有多... 查看详情

swift CoreData 谓词

】swiftCoreData谓词【英文标题】:swiftCoreDatapredicates【发布时间】:2016-08-1012:31:13【问题描述】:我正在将CoreData添加到我的应用程序中。简单的获取是可以的,但是当我尝试使用谓词获取数据时,我在AppDelegate中遇到异常。funcfetc... 查看详情

保存后CoreData objectID始终相同

】保存后CoreDataobjectID始终相同【英文标题】:CoreDataobjectIDisalwaysthesameaftersave【发布时间】:2015-07-0420:14:40【问题描述】:这是我的问题。我创建了一个coreDataNSManagedObject,保存它,它总是创建一个具有相同objectID的新对象......这... 查看详情

CoreData 谓词按日期

】CoreData谓词按日期【英文标题】:CoreDatapredicatebydate【发布时间】:2012-11-1705:43:08【问题描述】:我已经设置了一个coreData模型并添加了数据。我想搜索过去30天内的所有项目,然后将总单位数相加。这是我得到的:--(void)calculat... 查看详情

如何编辑保存在 CoreData 中的文本?

】如何编辑保存在CoreData中的文本?【英文标题】:HowtoedittextsavedinCoreData?【发布时间】:2019-05-1314:49:34【问题描述】:我将CoreData添加到我的Notes应用程序中。它保存数据,删除它等。现在我坚持编辑已经存在的笔记。好吧,我... 查看详情

使用swift使用谓词获取对象关系的coredata

】使用swift使用谓词获取对象关系的coredata【英文标题】:coredatafetchwithpredicateforobjectrelationusingswift【发布时间】:2017-10-2802:43:48【问题描述】:我正在尝试获取coreData中的实体。该实体与另一个实体具有一对一的关系。我只想获... 查看详情

IN 谓词在 SQL 中如何工作?

】IN谓词在SQL中如何工作?【英文标题】:HowdoestheINpredicateworkinSQL?【发布时间】:2010-10-2003:44:33【问题描述】:在为thisquestion准备答案后,我发现我无法验证我的答案。在我的第一份编程工作中,有人告诉我,IN()谓词内的查询... 查看详情