在NSPredicate中结合'AND'和'OR'条件

问题描述 投票:40回答:4

回来再次需要更多帮助构建我的NSPredicates :(

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

SubCategory
{
   name:string
   numbervalue:NSNumber
}

我想知道如何使用AND和OR创建谓词。

例如,我想返回名称为==“category_name”的每个类别,该类别还具有数值为“valueA”或“valueB”的子类别。

我已经尝试了所有可能的谓词构造函数组合,但是我无法让它工作。

到目前为止,这是我最好的尝试。

NSPredicate *predicate=[NSPredicate predicateWithFormat@"(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

我尝试过按数字值过滤,并完全保留了名称。

1)使用此结果即使集合中只有1个项具有该值,也会返回整个集合。

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

2)使用这会导致同样的问题,即使只有其中一个匹配,也会返回集合中的每个项目。

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

同样使用最简单的版本导致同样的问题....我之前没有注意到这一点。

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

所以我认为我的问题缩小了。

类别是实体。 SubCategory是一个实体。

类别与SubCategory具有一对多的关系,并表示为SubCategory的NSSet。

每个SubCategory都有一个名为numbervalue的属性。

编辑3

要测试我有2个分类。两个类别都有10个潜艇,每个潜艇的数值为1 -10;

使用此代码返回两个类别以及每个类别的所有10个子类。

预期的结果是两个类别都返回,每个类别只有2个潜艇。

我已经跟踪了所有对象并且数据是正确的。问题是我无法返回已过滤子类的类别。

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==%@).@count> 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();
}
ios core-data nspredicate
4个回答
34
投票

我将使用SUBQUERY执行以下操作。

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

试一试,让我知道。

另一种解决方案可能是获取整个集合subs,然后使用谓词过滤检索到的集合,以检查元素是否匹配value1value2

希望能帮助到你。

编辑

如果您遵循Eimantas的建议,请务必创建正确的数组:

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

71
投票

除了@Stuart的回答,你可以使用NSCompoundPredicate进行这样的OR&AND操作。

Obj-C - 或

// 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]];

斯威夫特 - 或者

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

斯威夫特 - 和

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

斯威夫特3 - 或

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

斯威夫特3 - 和

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

1
投票

另一个选择是使用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 :)


0
投票

这是你如何做到的:

SWIFT 4.x - AND

        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])
© www.soinside.com 2019 - 2024. All rights reserved.