Два контекста, 1 постоянное хранилище: повторяющиеся извлеченные записи

Я пытаюсь создать для пользователей способ импортировать контакты на свой телефон. Как это работает:

  • Существует два контекста управляемых объектов. «Настоящий» контекст имеет текущие данные в своей адресной книге. «Другой» контекст имеет входящие данные из другого источника. Оба используют один и тот же PersistentStoreCoordinator.

  • Я сопоставляю людей по электронной почте, поэтому, если контакт в «реальном» контексте совпадает с одним в «другом», я не сохраняю другой.

  • Когда я запускаю программу, у меня есть две записи в «реальном» контексте, которые я могу получить нормально.

  • Затем я импортирую два других контакта и добавляю их в «другой» контекст.

  • Когда я выполняю операцию выборки в «другом» контексте, я получаю ЧЕТЫРЕ результата — два из «реального» контекста и два, которые я только что добавил в «другой» контекст.

  • Однако, когда я сливаю изменения, моя схема обнаружения дубликатов работает.

Есть ли что-то, чего мне не хватает в моем понимании Core Data? Как я могу сделать так, чтобы мой запрос «другого» контекста просто возвращал новые результаты.

Полный код очень длинный, но вот важная часть:

AppDelegate *appDel = (AppDelegate*)[[UIApplication sharedApplication] delegate];

// Check to see the original data
NSManagedObjectContext *realContext = [appDel managedObjectContext];
NSFetchRequest *usersFetch= [[[NSFetchRequest alloc] init] autorelease];
[usersFetch setEntity:[NSEntityDescription entityForName:@"User" inManagedObjectContext:realContext]];
[usersFetch setSortDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"email" ascending:YES]]];

NSArray *users = [realContext executeFetchRequest:usersFetch error:&error];
[usersFetch release];
NSLog(@"%@",users);   // Returns 2 original objects already in database


otherContext = [[NSManagedObjectContext alloc] init];
[otherContext setPersistentStoreCoordinator:[[appDel managedObjectContext] persistentStoreCoordinator]];

for (contacts in fetchedData){
    User *newUser = (User*)[NSEntityDescription insertNewObjectForEntityForName:@"User" inManagedObjectContext:otherContext];
    newUser.email = fetchedData.email;
    newUser.firstName = fetchedData.firstName;
    // etc.
}

NSFetchRequest *newUsersFetch = [[[NSFetchRequest alloc] init] autorelease];
[newUsersFetch setEntity:[NSEntityDescription entityForName:@"User" inManagedObjectContext:otherContext]];
[newUsersFetch setSortDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"email" ascending:YES]]];
NSLog(@"%@",[otherContext registeredObjects]);   // 2 objects that were just added
NSArray *newUsers = [otherContext executeFetchRequest:newUsersFetch error:&error];
NSLog(@"%@",[otherContext registeredObjects]);  // 4 objects - added AND original
NSLog(@"Count: %i",[newUsers count]);                  // Count: 4

person Michael D.    schedule 07.09.2011    source источник


Ответы (1)


Я думаю, что вы можете концептуально путать контексты управляемых объектов с постоянным хранилищем. У вас может быть произвольное количество контекстов, прикрепленных к определенному хранилищу, и изменения, сделанные в любом отдельном контексте, в конечном итоге отобразятся во всех остальных.

Это особенно верно для выборок, которые идут непосредственно в магазин, чтобы найти объекты. Ваш код работает должным образом, если вы вызываете save в контексте other. Как только вы сохраните объект, он попадет в постоянное хранилище и будет отображаться во всех широких выборках сущностей.

Не следует создавать управляемые объекты, которые могут иметь дубликаты. Вместо этого обычной практикой является извлечение новых значений, чтобы проверить, существуют ли они уже, и создание нового управляемого объекта со значением только в том случае, если значение еще не существует в хранилище. Чтобы сделать это быстро, вы можете выполнить выборку для определенного свойства и посмотреть, возвращается ли что-нибудь.

person TechZen    schedule 07.09.2011
comment
Понял - так создавайте новые объекты, только если их нет в БД. Другой контекст можно использовать для постепенного создания записей до тех пор, пока они не будут готовы к сохранению, после чего изменения можно будет объединить. - person Michael D.; 07.09.2011
comment
Вы редко получаете большое преимущество, используя два или более контекста в одном потоке. Поскольку все это происходит в основном потоке, вы можете просто использовать один контекст, а затем откатить или удалить любые объекты, которые вы решили не сохранять. - person TechZen; 08.09.2011