web-dev-qa-db-ja.com

NSPredicateで「AND」条件と「OR」条件を組み合わせる

NSPredicatesを構築するのにさらに助けが必要になります:(

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

SubCategory
{
   name:string
   numbervalue:NSNumber
}

[〜#〜] and [〜#〜]および[〜#〜] or [〜#〜]で述語を作成する方法を知りたい。

たとえば、「= valueA」の数値を持つサブカテゴリも持つ、name ==「category_name」のすべてのカテゴリを返したいと思います[〜#〜] or [〜#〜] "valueB" 。

私は思いつく可能性のある述語コンストラクタの可能な組み合わせをすべて試しましたが、それを機能させることはできません。

これはこれまでの私の最善の試みです。

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

編集1

2回目の試行。 「数値」のフィルタリングはまだ機能していません。

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)これを使用すると、セット内の1つのアイテムのみに値がある場合でも、セット全体が返されます。

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

2)これを使用すると、同じ問題が発生します。1つしか一致しない場合でも、セット内のすべてのアイテムが返されます。

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と1対多の関係にあり、SubCategoryのNSSetとして表されます。

各SubCategoryには、numbervalueという名前の属性があります。

編集

テストするには、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();
}
42
dubbeat

SUBQUERYを使用して以下を実行します。

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

それを試して、私に知らせてください。

別の解決策としては、コレクションsubs全体を取得してから、取得したセットを述語でフィルター処理して、要素がvalue1またはvalue2に一致するかどうかを確認することができます。

それが役に立てば幸い。

編集

Eimantasの提案に従う場合は、正しい配列を作成してください。

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

@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-AND

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

スウィフト3-AND

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

別のオプションは、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 :)

1
Stuart P.

これはあなたがそれを行う方法です:

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-OR

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

Swift 4.x-NOT

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

これは私のコードの1つの例で、uidとsyncを探します。

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