Core Data - фильтрация отношений To-Many с использованием Predicates

В моей базовой модели данных у меня есть следующие два объекта:

Manufacture {name, ...other attributes}
Product {name, .... other attributes}

У меня есть отношение "От одного до большого":

Manufacturer.manufactures <------>> Product.manufacturedBy

Я пытаюсь создать предикат для возврата всех Продуктов, принадлежащих Производителям, которые соответствуют строке поиска. Например. если есть два производителя, "King Nut" и "Queen Nut", то поиск в "Гайке" должен вернуть все продукты, сделанные как King Nut, так и Queen Nut.

Мой предикат отлично работает, когда мой фильтр находится в объекте Product, однако я не могу заставить предикат работать при фильтрации на объекте Manufacturer. Набор результатов пуст.

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Product" inManagedObjectContext:[GBKDB context]];
searchValue = @"nut";
NSString *wildcardString = [NSString stringWithFormat:@"*%@*", searchValue];

Я пробовал следующее:

    predicate = [NSPredicate predicateWithFormat:@"manufacturedBy.name CONTAINS[cd] %@",searchValue];
    predicate = [NSPredicate predicateWithFormat:@"manufacturedBy.name like %@",wildcardString];
    predicate = [NSPredicate predicateWithFormat:@"manufacturedBy.name matches %@",wildcardString];
    predicate = [NSPredicate predicateWithFormat:@"ALL manufacturedBy.name like %@",wildcardString];
    predicate = [NSPredicate predicateWithFormat:@"ALL manufacturedBy.name like[cd] %@",@wildcardString];

Ответ 1

Чтобы получить Product, изготовленный изготовителем с именем, содержащим "гайку", ваш запрос должен выглядеть так:

NSString* searchVal = @"nut";
NSFetchRequest* r = [[NSFetchRequest alloc] initWithEntityName:@"Product"];
[r setPredicate:[NSPredicate predicateWithFormat:@"manufacturedBy.name CONTAINS[cd] %@",searchVal]];

Чтобы получить Manufacturer с названиями продуктов, содержащими "гайку", ваш запрос должен выглядеть так:

NSString* searchVal = @"nut";
NSFetchRequest* r = [[NSFetchRequest alloc] initWithEntityName:@"Manufacture"];
[r setPredicate:[NSPredicate predicateWithFormat:@"ANY manufactures.name CONTAINS[cd] %@",searchVal]];

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

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

typedef void(^config_block_t)(id);

- (void) synthesizeObjectsOfEntity:(NSString*)entity
                           context:(NSManagedObjectContext*)context
                             count:(NSUInteger)count
                       configBlock:(config_block_t)configBlock
{
    for (;count;--count) {
        NSManagedObject* object = [NSEntityDescription insertNewObjectForEntityForName:entity
                                                                inManagedObjectContext:context];
        configBlock(object);
    }
}

- (void) synthesizeProductsAndManufacturersInContext:(NSManagedObjectContext*)context
{
    NSMutableArray* manufacturers = [NSMutableArray new];
    [self synthesizeObjectsOfEntity:@"Manufactur"
                            context:context
                              count:10
                        configBlock:^(Manufactur* m) {
                            m.name = [NSString stringWithFormat:@"m-%u%u%u",arc4random()%10,arc4random()%10,arc4random()%10];
                            [manufacturers addObject:m];
                        }];
    [self synthesizeObjectsOfEntity:@"Product"
                            context:context
                              count:100
                        configBlock:^(Product* p) {
                            p.name = [NSString stringWithFormat:@"p-%u%u%u",arc4random()%10,arc4random()%10,arc4random()%10];
                            p.manufacturedBy = manufacturers[arc4random() % [manufacturers count]];
                        }];
    [context save:NULL];
    [context reset];
    NSString* searchVal = @"3";
    NSFetchRequest* r = [[NSFetchRequest alloc] initWithEntityName:@"Product"];
    [r setPredicate:[NSPredicate predicateWithFormat:@"manufacturedBy.name CONTAINS[cd] %@",searchVal]];
    NSArray* match = [context executeFetchRequest:r error:NULL];
    NSLog(@"matched: %u",[match count]);
}

Ответ 2

Взгляните на этот документ от Apple. Он делает пример того, что вы пытаетесь сделать с предикатом "ЛЮБОЙ".