Coredata выборки и группировки объектов в разделах - PullRequest
2 голосов
/ 16 августа 2011

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

Мне нужно сгруппировать Meeting managedобъекты в несколько разных «карманов», таких как проект, клиент и несколько других.По нескольким причинам я решил реализовать их как теги, которые можно связать с сущностью Meeting.

Итак, я создал новую сущность Tag, которая имеет тип и значение, и установил отношения между ними:

Meeting <<-->> Tag

Если я хочу связать Встречу с проектомЯ создаю тег с именем «project» и значением «Project Name», а затем добавляю его в сущность «Meeting» через отношение.

Сначала я думал об использовании NSFetchedResultsController, но у меня возникают все виды проблем.из которых я не совсем понимаю.

Например, эта выборка (я опускаю ненужные биты):

NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:[Meeting entityName] inManagedObjectContext:moc];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"tags.name contains[] 'client'"];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"title" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
[fetch setEntity:entity];
[fetch setPredicate:predicate];
[fetch setSortDescriptors:sortDescriptors];
NSFetchedResultsController *frc = [[NSFetchedResultsController alloc] initWithFetchRequest:fetch 
                                                                      managedObjectContext:moc 
                                                                        sectionNameKeyPath:@"self.tags.value" 
                                                                                 cacheName:nil];

В данном конкретном случае выборка работает, но каким-то образом яя получаю неожиданные результаты, в которых представлены не только Tags со значением client, но также и со значением project ???

Если я изменю свой предикат на tags.name == 'project', я получаю исключение:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'to-many key not allowed here'

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

В качестве дополнительного вопроса, который я тоже не понимаю, почему я должен добавить self в мой sectionNameKeyPath в self.tags.value?Что оно делает??В этом случае, если я не добавлю его, я также получу исключение:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid to many relationship in setPropertiesToFetch: (tags.value)

Наконец, какова альтернатива использованию контроллера извлеченных результатов в этом случае?Будут ли это куча запросов на выборку, где я сначала получу каждый экземпляр Tag, где name == 'project', и переберу массив, чтобы извлечь объекты Meeting, связанные с ним?Это кажется крайне неэффективным, но все, о чем я могу думать в данный момент, поэтому, если у вас есть какие-либо другие идеи, мне очень интересно их услышать.

Заранее большое спасибо за ваше время,

Рог

Ответы [ 2 ]

3 голосов
/ 16 августа 2011

Проблема в том, что Meeting has-many tags, поэтому вам нужно будет использовать агрегатные операции:

NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:[Meeting entityName] inManagedObjectContext:moc];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"ANY tags.name contains[cd] 'client'"];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"title" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
[fetch setEntity:entity];
[fetch setPredicate:predicate];
[fetch setSortDescriptors:sortDescriptors];
NSFetchedResultsController *frc = [[NSFetchedResultsController alloc] initWithFetchRequest:fetch 
managedObjectContext:moc 
sectionNameKeyPath:@"clientName"
cacheName:nil];

т.е. дать мне список всех Meeting объектов, гдеANY из tags относятся к типу client и группируют их по clientName.Чтобы ключ clientName работал, вам нужно реализовать временное свойство:

- (NSString *)clientName {
    [self willAccessValueForKey:@"clientName"];

    // Set clientName to the value of the first tag with name 'client'
    NSString* clientName = @"...";

    [self didAccessValueForKey:@"clientName"];
    return clientName;
}

Если для ряда ваших подклассов NSManagedObject требуется свойство clientName, вы можете реализовать его вобщий абстрактный NSManagedObject подкласс, и ваши конкретные подклассы наследуются от него.

1 голос
/ 16 августа 2011

«Документация Apple по [NSPredicate] оставляет желать лучшего» - полностью согласен!

tags.name недопустимо, потому что теги - это коллекция, нет объекта, их (скажем, три)

Я думаю, вы хотите что-то вроде "tags contains %@", projectTag, но я не уверен в синтаксисе. может быть "%@ IN %@", projectTag, thing.tags

...