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

时间:2014-06-06 15:28:00

标签: ios objective-c core-data nspredicate

巨大的更新:

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

这是我的数据模型:

enter image description here

enter image description here

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文件,看看到底是什么。

enter image description here

enter image description here

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

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

- (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

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

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

最后,在我保存上下文后,再次只有一个对象。


只是忽略这个

- 下面的旧信息

我的代码如下:

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

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

fetch界面的工作方式如下:

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;

让我感到困惑的是,使用相同的获取请求,为什么在保存后会返回不同的结果?

以下是更多细节:

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

<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>"
    );
}

打印所有任务的描述:

<_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:
#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:&error,错误是零。

2 个答案:

答案 0 :(得分:1)

节省了什么?

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

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

答案 1 :(得分:0)

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

例如,如果您创建一个没有反比关系的多对多关系,Taskwatchers之间存在多对多关系Person,但Person不会与Task相反,然后关系字段watchers将放在Person表而不是中间/映射表中。

在这种情况下,我在Person t1 Task中添加watchers p1会将watchers提交到1 Person更新Person } table。

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

enter image description here

因此,一个Task只能指向一个Person

通过添加从Task到{{1}}的反向关系可以解决此问题。