49

NSPredicates の構築についてさらに支援が必要です :(

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

SubCategory
{
   name:string
   numbervalue:NSNumber
}

ANDORで述語を作成する方法を知りたいです。

たとえば、name == "category_name" のすべてのカテゴリを返したいと思います。これには、"valueA" OR "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

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 という名前の属性があります。

編集 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();
}
4

4 に答える 4

85

@Stuart の回答に加えて、このような OR & AND 操作に NSCompoundPredicate を使用できます。

オブジェクト C - または

// OR Condition //

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

オブジェクト 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])
于 2015-12-10T23:11:36.470 に答える
37

を使用して次のことを行います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];
于 2012-04-25T14:47:15.417 に答える
1

もう 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 :)

于 2015-11-19T23:16:07.563 に答える