NSFetchRequest не перехватывает объекты с измененным свойством - PullRequest
4 голосов
/ 20 августа 2011

Я столкнулся со странной проблемой с CoreData на MacOsX 10.6 с использованием хранилища SQL.У меня есть NSManagedObject подкласс с именем Family с атрибутом name и отношение personList, связанное с другим NSManagedObject подклассом с именем Person с атрибутом firstname и обратным отношением familyPerson есть только один family, а у family может быть несколько Person с.

Скажем, у меня есть Family объект family, указывающий на семью «Доу» с 2Person (Джон и Джейн) подключились к нему, и я делаю следующий запрос:

NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:[NSEntityDescription entityForName:@"Person" inManagedObjectContext:managedObjectContext]];
[request setPredicate:[NSPredicate predicateWithFormat:@"family.name=%@",[family name]]];
NSArray *array = [managedObjectContext executeFetchRequest:request error:&error];

Я получаю массив размера 2 с двумя людьми: Джейн и Джон, с фамилией Доу.Теперь, если я обновлю Семейство, используя его синтезированный метод доступа, в моем случае:

[family setName:@"Wheat"]

Я не смогу получить список Person, используя тот же запрос на выборку.В результате получается [array count] из 0.

Если я изменю предикат на следующую строку, он снова работает:

[request setPredicate:[NSPredicate predicateWithFormat:@"family=%@",family]];

Так что, как будто Предикат неиспользуя обновленную версию имени свойства семейства, даже если у меня для NSFetchRequest установлены значения по умолчанию (поэтому includesPendingChanges возвращает YES).Это не имеет смысла для меня.Кажется, что NSFetchRequest находит объект family, но не видит, что его значение family.name было обновлено, а не сохранено и находится в managedObjectContext в памяти.Конечно, если я сохраню магазин, он снова заработает.

Есть идеи?Я просмотрел документацию по Mac и не могу понять, почему это не получится.

Ответы [ 3 ]

4 голосов
/ 20 августа 2011

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

Из Руководства по программированию основных данных:

Вы не можете получить с помощью предиката, основанного на переходных свойствах (хотя вы можете использовать переходные свойства для фильтрации в памяти сам). Более того, есть некоторые взаимодействия между извлечением и тип магазина - подробности см. в разделе «Типы магазинов и их поведение». Подводя итог, однако, если вы выполняете выборку напрямую, вы должны обычно не добавляют предикаты Objective-C или сортируют дескрипторы запрос на получение. Вместо этого вы должны применить их к результатам выборка Если вы используете контроллер массива, вам может понадобиться создать подкласс NSArrayController, чтобы вы могли не передавать дескрипторы сортировки постоянное хранилище и вместо этого выполните сортировку после того, как ваши данные был доставлен.

2 голосов
/ 20 августа 2011

Подводя итог, я тщательно протестировал свой код, и вот как я воспринимаю ограничения CoreData в отношении выборки и предиката target-c (т. Е. Точечная запись).

Если к объекту был получен доступ из программы Objective-C и если было изменено одно из его свойств или отношений, любой NSFetchRequest с предикатом, использующим точечную нотацию, вернет структуру хранилища SQL, следовательно, результаты будут ошибочными.

В случае тривиального примера Family и Person , если у вас есть ссылка на Family и измените ее имя любой запрос, сделанный для Person NSEntity, не может содержать предикат со следующим элементом запроса

@ "family.name =% @"

Это действительно запрос с использованием фамилии в хранилище SQL. Однако после такого изменения будет работать следующий запрос:

@ "семья =% @"

Действительно, NSFetchRequest по-прежнему будет извлекать информацию из хранилища, но, поскольку структура не изменилась, он заменит объекты, извлеченные теми, которые находятся в памяти, поэтому последующий тест [ фамилия] вернет обновленное имя.

С осторожностью вы можете использовать вложенный предикат, такой как:

@ "person.family.name =% @"

Пока вы можете гарантировать, что все объекты, которые имеют свойство person , не изменили ни их семейство , ни их имя . Если это не так, то вы можете в лучшем случае позвонить

@ "person.family =% @"

Или, если вы не можете гарантировать, что все объекты Family не тронуты, только

@ "человек =% @"

Конечно, альтернативой является систематическое SAVE: NSManagedObjects в постоянное хранилище каждый раз, когда вы вносите какие-либо изменения, поэтому все свойства обновляются, и тогда все вышеприведенные нотации будут работать. Однако бывают случаи, когда вы хотите предотвратить сбережения и заставить клиента изменить свой документ, только если он пожелает (подумайте об инструментах Word, Excel, Picture и т. Д.). Надеюсь, что это поможет.

0 голосов
/ 20 августа 2011

Если под «использованием одного и того же запроса на выборку» вы имеете в виду использование того же самого экземпляра запроса на выборку, который вы создали в первый раз, то это неудивительно.Предикат, который вы применили, это "family.name = Doe".Если имя семейства «Пшеница», предикат запроса на выборку больше не соответствует ему, потому что «Пшеница»! = «Доу».

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

Если под "использованием одного и того же запроса на выборку" вы подразумеваете использование другого запроса на выборку, построенного с использованием того же кода, тогда я подумаю@ Ответ Мунди.

...