Основные данные: как проверить наличие связи «многие ко многим»
Вопрос
У меня есть "Песня" Сущность и «тег» сущность, и они имеют много-много отношений между ними. Песня может иметь несколько тегов, а тег может быть применен к нескольким песням.
Я хочу проверить, связан ли с песней определенный тег. Если с композицией связан тег, я хочу показать галочку в табличном представлении.
По аналогичной логике в Apple " TaggedLocations " В примере кода выполняется следующая проверка для проверки наличия связи.
if ([event.tags containsObject:tag]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
Это может быть неэффективно, если в базе данных много тегов, поскольку они будут извлекать все из них в памяти. Пожалуйста, поправьте меня, если я здесь не прав.
Есть ли более эффективный способ проверить, связана ли песня с определенным тегом, вместо проверки в Song.Tags?
Решение
Это на самом деле довольно легко сделать, если полностью без документов. Вы хотите создать запрос на выборку с предикатом, у которого есть операция set. Если мы представим, что в вашей модели тегов есть свойство tagValue, предикат, который вас интересует, это «ANY tags.tagValue == 'footag' "
NSString *tagSearch = @"footag";
// However you get your NSManagedObjectContext. If you use template code, it's from
// the UIApplicationDelegate
NSManagedObjectContext *context = [delegate managedObjectContext];
// Is there no shortcut for this? Maybe not, seems to be per context...
NSEntityDescription *songEntity = [NSEntityDescription entityForName:@"Song" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:songEntity];
// The request looks for this a group with the supplied name
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"ANY tags.tagValue == %@", tagSearch];
[request setPredicate:predicate];
NSError *error = nil;
NSArray *results = [context executeFetchRequest:request error:&error];
[request release];
Другие советы
Вы правы, используя этот код, вы получите весь набор, и сравнение объектов может быть довольно сложным, в зависимости от того, сколько свойств и отношений являются частью объекта объекта.
В любом случае, вы не можете избежать набора сравнения для включения. Вероятно, лучшее, что вы можете сделать, это избежать выборки всех свойств / отношений, попросив Базовые Данные получать только объекты NSManagedObjectID.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:@"Tag" inManagedObjectContext:[self managedObjectContext]]];
[fetchRequest setResultType:NSManagedObjectIDResultType];
NSManagedObjectID объекты гарантированно являются уникальными, поэтому вы можете безопасно использовать их для проверки на включение набора. Это должно быть гораздо более эффективным с точки зрения производительности.