在我的应用中,我在标签和链接之间存在多对多关系,如下所示:
Tags <<-->> Links
我正在尝试返回与具有当前活动标记的链接相关的标记列表,但不包含在活动标记中。
我还想获得具有“其他”标签的链接数量的计数,这些标签需要受活动标签的限制。
使用下面的代码,我可以返回“其他”标签和链接数,但返回的计数是每个标签的所有链接。
我希望能够使用与我用于构建子查询的方法类似的方法来计算链接,但我正在努力使其工作。我已经尝试使用count 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];
非常感谢任何帮助!
答案 0 :(得分: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];