Подтвердить что ты не робот

Объединение условий "AND" и "OR" в NSPredicate

Еще раз нужна дополнительная помощь при построении моих NSPredicates: (

Category
{
   name:string
   subs<-->>SubCategory
}

SubCategory
{
   name:string
   numbervalue:NSNumber
}

Я хотел бы знать, как создать предикат с И и ИЛИ.

Например, я хотел бы возвратить каждую категорию с именем == "category_name", которое также имеет подкатегорию с numbervalue "valueA" ИЛИ "значениеB".

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

Это моя лучшая попытка.

NSPredicate *predicate=[NSPredicate [email protected]"(name== %@) AND (ANY subs.numbervalue==%@ OR ANY subs.numbervalue==%@)", @"aname", value1, value2];

Изменить 1

Вторая попытка. Фильтрация на "numbervalue" все еще не работает.

NSNumber valueA=[NSNumber numberWithInt:20];
NSNumber valueA=[NSNumber numberWithInt:90];
NSArray *arr=[NSArray arrayWithObject:valueA,valueB,nil];

predicate=[NSPredicate predicateWithFormat:@"(name==%@)AND(ANY subs.numbervalue IN %@)",@"aname",arr];

Изменить 2

Я пробовал фильтрацию только с помощью numberValue и оставил имя alltogether.

1), используя это, приводит к возврату всего набора, даже если только 1 элемент в наборе имеет значение.

predicate=[NSPredicate predicateWithFormat:@"(ANY subs.numbervalue IN %@)",arr];

2) Используя этот результат в той же самой задаче, каждый элемент в наборе возвращается, даже если только 1 из них соответствует.

predicate=[NSPredicate predicateWithFormat:@"((SUBQUERY(subs, $x, $x.numbervalue == %@ or $x.numbervalue == %@)[email protected] > 0)", value1, value2];

Также использование простейшей версии приводит к той же проблеме.... Я этого раньше не заметил.

NSPredicate *predicate=[NSPredicate [email protected]"(ANY subs.numbervalue==%@ ,valueA];

Итак, я думаю, что моя проблема сузилась.

Категория - это объект. SubCategory - это сущность.

Категория имеет отношение "один-много" к подкатегории и представлено как NSSet подкатегории.

Каждая подкатегория имеет атрибут с именем numbervalue.

Изменить 3

Чтобы проверить, у меня есть 2 категории. Обе категории имеют 10 подсетей, каждый с numbervalue 1 -10;

Используя этот код, обе категории возвращаются вместе со всеми 10 подмножествами для каждого.

Ожидаемый результат: возвращаются обе категории, каждая с двумя слотами.

Я проследил все мои объекты, и данные верны. Проблема в том, что я не могу вернуть категорию, которая отфильтровала subs.

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSManagedObjectContext *context=[[DataSource sharedDataSource]managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Category" inManagedObjectContext:context];
[fetchRequest setEntity:entity];

[fetchRequest setFetchBatchSize:20];

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];

NSPredicate *predicate;
NSNumber *a=[NSNumber numberWithFloat:1];
NSNumber *b=[NSNumber numberWithFloat:2];
predicate=[NSPredicate predicateWithFormat:@"(SUBQUERY(subs,$x,$x.numbervalue==%@ or $x.numbervalue==%@)[email protected]> 0)",a,b];

[fetchRequest setPredicate:predicate];
[fetchRequest setSortDescriptors:sortDescriptors];

NSError *error = nil;
[NSFetchedResultsContoller deleteCacheWithName:nil];

NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:@"name" cacheName:@"Master"];
aFetchedResultsController.delegate = self;

self.fetchedResultsController = aFetchedResultsController;

if (![self.fetchedResultsController performFetch:&error]) {

   NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
   abort();
}
4b9b3361

Ответ 1

Я сделаю следующее, используя SUBQUERY.

[NSPredicate [email protected]"(name == %@) AND (SUBQUERY(subs, $x, $x.numbervalue == %@ or $x.numbervalue == %@)[email protected] > 0)", @"aname", value1, value2];

Попробуйте и дайте мне знать.

Другим решением может быть захват всей коллекции subs, а затем фильтрация полученного набора с помощью предиката, чтобы проверить, соответствуют ли элементы для value1 или value2.

Надеюсь, что это поможет.

Edit

Если вы следуете рекомендациям Eimantas, обязательно создайте правильный массив:

NSNumber valueA = [NSNumber numberWithInt:20];
NSNumber valueB = [NSNumber numberWithInt:90];
NSArray *arr = [NSArray arrayWithObjects:valueA, valueB, nil];

Ответ 2

Дополнение к ответу @Stuart, вы можете использовать NSCompoundPredicate для своих операций OR и AND, как это.

Obj-C - OR

// OR Condition //

NSPredicate *predicate1 = [NSPredicate predicateWithFormat:@"X == 1"];
NSPredicate *predicate2 = [NSPredicate predicateWithFormat:@"X == 2"];
NSPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:@[predicate1, predicate2]];

Obj-C - AND

NSPredicate *predicate1 = [NSPredicate predicateWithFormat:@"X == 1"];
NSPredicate *predicate2 = [NSPredicate predicateWithFormat:@"X == 2"];
NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[predicate1, predicate2]];

Swift - OR

let predicate1:NSPredicate = NSPredicate(format: "X == 1")
let predicate2:NSPredicate = NSPredicate(format: "Y == 2")
let predicate:NSPredicate  = NSCompoundPredicate(orPredicateWithSubpredicates: [predicate1,predicate2] )

Swift - И

let predicate1:NSPredicate = NSPredicate(format: "X == 1")
let predicate2:NSPredicate = NSPredicate(format: "Y == 2")
let predicate:NSPredicate  = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate1,predicate2] )

Swift 3 - OR

    let predicate1 = NSPredicate(format: "X == 1")
    let predicate2 = NSPredicate(format: "Y == 2")
    let predicateCompound = NSCompoundPredicate.init(type: .or, subpredicates: [predicate1,predicate2])

Swift 3 - AND

    let predicate1 = NSPredicate(format: "X == 1")
    let predicate2 = NSPredicate(format: "Y == 2")
    let predicateCompound = NSCompoundPredicate.init(type: .and, subpredicates: [predicate1,predicate2])

Ответ 3

Другой вариант - использовать NSCompoundPredicate (примечание andPredicateWithSubpredicates делает AND, но есть несколько вариантов использования, это должно быть намного более эффективно, чем выполнение 2 запросов)

https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSCompoundPredicate_Class/index.html#//apple_ref/occ/clm/NSCompoundPredicate/andPredicateWithSubpredicates:)

Ответ 4

Вот как вы можете это сделать:

SWIFT 4.x - И

        let p0 = NSPredicate(format: "X == 1")
        let p1 = NSPredicate(format: "Y == 2")
        fetchRequest.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [p0, p1])

SWIFT 4.x - ИЛИ

        let p0 = NSPredicate(format: "X == 1")
        let p1 = NSPredicate(format: "Y == 2")
        fetchRequest.predicate = NSCompoundPredicate(orPredicateWithSubpredicates: [p0, p1])

SWIFT 4.x - НЕ

        let p0 = NSPredicate(format: "X == 1")
        let p1 = NSPredicate(format: "Y == 2")
        fetchRequest.predicate = NSCompoundPredicate(notPredicateWithSubpredicates: [p0, p1])

пример

Это пример из одного из моих кодов, где я ищу uid и синхронизацию:

        let p0 = NSPredicate(format: self.uid + " = '" + uid + "'")
        let p1 = NSPredicate(format: self.sync + " = %@", NSNumber(value: true as Bool))
        fetchRequest.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [p0, p1])

Ответ 5

спасибо за отличную информацию. Можно ли использовать предикат с 3 или более условиями AND?

let p0 = NSPredicate(format: "X == 1")
let p1 = NSPredicate(format: "Y == 2")
let p2 = NSPredicate(format: "Z == 3")
fetchRequest.predicate = NSCompoundPredicate(notPredicateWithSubpredicates: [p0, p1,p2])