0

私のアプリでは、次のようにタグとリンクの間に多対多の関係があります。

Tags <<-->> Links

現在アクティブなタグを持つリンクに関連するタグのリストを返そうとしていますが、アクティブなタグには含まれていません。

また、アクティブなタグによって制限する必要がある「その他」のタグを持つリンクの数を取得したいと考えています。

以下を使用して、「その他」のタグとリンクの数を返すことができましたが、返された数は各タグのすべてのリンクです。

サブクエリの作成に使用しているものと同様のアプローチを使用してリンクをカウントできるようにしたいのですが、それを機能させるのに苦労しています。カウント NSExpression で生成されたサブクエリを使用しようとしましたが、サブクエリが評価されるとこのエラーが発生します。

// Test array of tag names
self.activeTagArray = [@[@"tag1", @"tag2"] mutableCopy];

NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:[Tag entityName]];

// We want to exclude the tags that are already active
NSPredicate *activeTagsPredicate = [NSPredicate predicateWithFormat:@"NOT ANY name IN %@", self.activeTagArray];

// Build subquery string to identify links that have all of the active tags in their tag set
NSString __block *subquery = @"SUBQUERY(links, $link, ";

[self.activeTagArray enumerateObjectsUsingBlock:^(id tagName, NSUInteger index, BOOL *stop) {
    if (index == self.activeTagArray.count - 1) {
        subquery = [subquery stringByAppendingString:[NSString stringWithFormat:@"SUBQUERY($link.tags, $tag, $tag.name = '%@') != NULL", tagName]];
    } else {
        subquery = [subquery stringByAppendingString:[NSString stringWithFormat:@"SUBQUERY($link.tags, $tag, $tag.name = '%@') != NULL AND ", tagName]];
    }
}];

subquery = [subquery stringByAppendingString:@") != NULL"];

NSLog(@"Subquery : %@", subquery);

NSPredicate *noTagsPredicate = [NSPredicate predicateWithFormat:subquery];


// Create a predicate array
NSArray *predicateArray = @[noTagsPredicate, activeTagsPredicate, userPredicate];
NSPredicate *compoundPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:predicateArray];

fetchRequest.predicate = compoundPredicate;
fetchRequest.relationshipKeyPathsForPrefetching = @[@"links"];

// Set up the count expression
NSExpression *countExpression = [NSExpression expressionForFunction: @"count:" arguments:@[[NSExpression expressionForKeyPath: @"links.href"]]];


NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];

expressionDescription.name = @"counter";
expressionDescription.expression = countExpression;
expressionDescription.expressionResultType = NSInteger32AttributeType;

fetchRequest.propertiesToFetch = @[@"name", expressionDescription];

// Sort by the tag name
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
fetchRequest.sortDescriptors = @[sortDescriptor];

fetchRequest.resultType = NSDictionaryResultType;

NSError *error = nil;

NSArray *resultsArray = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (error) {
    NSLog(@"Error : %@", [error localizedDescription]);
}

NSMutableArray *allTags = [[NSMutableArray alloc] init];
for (NSDictionary *tagDict in resultsArray) {
    NSLog(@"Tag name : %@, Link Count : %@", tagDict[@"name"], tagDict[@"counter"]);
    [allTags addObject:tagDict[@"name"]];
}

[allTags addObjectsFromArray:self.activeTagArray];

これについて何か助けていただければ幸いです。

4

1 に答える 1

0

あなたの質問を正しく理解している場合、次の述語はあなたの「その他のタグ」​​、つまり、指定されたすべての「アクティブなタグ」に関連するリンクに関連するすべてのタグを取得します。

NSArray *activeTags = @[@"tag1", @"tag2"];

NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Tag"];

NSPredicate *p1 = [NSPredicate predicateWithFormat:@"NOT name in %@", activeTags];
NSPredicate *p2 = [NSPredicate predicateWithFormat:@"SUBQUERY(links, $l, SUBQUERY($l.tags, $t, $t.name IN %@).@count = %d).@count > 0",
                   activeTags, [activeTags count]];
NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[p1, p2]];
[request setPredicate:predicate];

そして今、「トリック」: 述語 p2 の左側は

SUBQUERY(links, $l, SUBQUERY($l.tags, $t, $t.name IN %@).@count = %d).@count

これはまさに結果に含まれるリンクの数であるため、その述語から式の説明を作成できます。

NSExpression *countExpression = [(NSComparisonPredicate *)p2 leftExpression];

NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];
expressionDescription.name = @"counter";
expressionDescription.expression = countExpression;
expressionDescription.expressionResultType = NSInteger32AttributeType;

[request setResultType:NSDictionaryResultType];
[request setPropertiesToFetch:@[@"name", expressionDescription]];

結果の SQLite クエリは非常に複雑です。最初にリンクを取得するのが賢明かもしれません:

NSFetchRequest *linkRequest = [NSFetchRequest fetchRequestWithEntityName:@"Link"];
NSPredicate *linkPredicate = [NSPredicate predicateWithFormat:@"SUBQUERY(tags, $t, $t.name IN %@).@count = %d",
                              activeTags, [activeTags count]];
[linkRequest setPredicate:linkPredicate];
NSArray *activeLinks = [context executeFetchRequest:linkRequest error:&error];

p2別のステップでタグをフェッチします。これは、述語のみがより単純なサブクエリに置き換えられる上記のコードで実行できます

NSPredicate *p2 = [NSPredicate predicateWithFormat:@"SUBQUERY(links, $l, $l IN %@).@count > 0", activeLinks];
于 2013-08-08T15:32:40.520 に答える