【问题标题】:Combining 'AND' and 'OR' Condition in NSPredicate在 NSPredicate 中结合 'AND' 和 'OR' 条件
【发布时间】:2012-05-06 06:10:37
【问题描述】:

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

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

SubCategory
{
   name:string
   numbervalue:NSNumber
}

我想知道如何使用 ANDOR 创建谓词。

例如,我想返回名称 == "category_name" 的每个类别,该类别也有一个数字值为 "valueA" OR "valueB" 的子类别。

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

这是我迄今为止最好的尝试。

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

编辑 1

第二次尝试。对“数值”的过滤仍然不起作用。

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 进行过滤,并将名称全部省略。

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 是一个实体。

Category 与 SubCategory 是一对多的关系,表示为 SubCategory 的 NSSet。

每个子类别都有一个名为 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();
}

【问题讨论】:

  • 你检查过NSCompoundPredicate吗?它应该可以帮助你。也尝试使用... AND (ANY subs.numberValue IN %@)", @"fooName", numArray
  • 使用 $x.numbervalue 而不是 $numbervalue。然后先尝试将缓存设置为nil,看看结果。
  • @Flex_Addicted。感谢你的帮助。最后,我不得不在 numberofrowsinsection 等函数中过滤我的 category.subs。这有点骇人听闻,但它似乎正在工作

标签: ios core-data nspredicate


【解决方案1】:

除了@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 - 与

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] )

Swift 3 - 或

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

Swift 3 - 与

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

【讨论】:

  • 太棒了!我想要完全一样的东西。
【解决方案2】:

我将使用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];

【讨论】:

  • 似乎正在发生的事情是,例如,如果 subs 集合的数值为 90,但其余部分为 0,则仍会返回整个 subs 集合
  • 尝试只使用 (SUBQUERY(subs, $x, $x.numbervalue == %@ or $x.numbervalue == %@).@count > 0) 在谓词中并使用附加谓词过滤数组以查找该名称。
  • 仅使用 SUBQUERY 检索到什么结果?
  • 我更新了我的答案。无论我做什么,每个 subs 中的每个条目都会返回,即使其中只有一个具有正确的值。
  • @dubbeat 这很奇怪。 NSPredicate 是正确的。我在一个项目中尝试过它并且它有效。如果您使用 slqlite 作为支持存储,建议很少。首先使用debugging-core-data-on-the-iphone启用跟踪sql操作。然后尝试探索插入到数据库中的数据。两种方法:加载托管对象并使用 NSLog 打印它们或直接浏览您的 sqllite 文件。也许你会发现一些奇怪的东西,也许是因为你以错误的方式创建了数据。这只是一个假设。希望对您有所帮助。
【解决方案3】:

对于 Swift,您可以这样做:

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])

【讨论】:

【解决方案4】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-28
    • 2012-08-03
    • 2012-11-03
    • 2014-11-23
    • 2015-02-14
    • 1970-01-01
    • 2015-09-17
    • 1970-01-01
    相关资源
    最近更新 更多