0

我一直在尝试使用 Core Data 解决以下问题,但没有任何运气。

我的模型有两个实体:Group 和 Element。都具有“名称”属性和以下形式的一对多关系:“group.elements”和“element.groups”(属于多个组的元素和具有多个元素的组)

我想以以下形式建立一个“过滤器”:

elements that belongs to "group_A" AND "group_B"

为了向用户显示如下内容:

The elements that match the filter belong to this set of groups in that quantity

例如,有类似的东西:

Element_1 Group_A、Group_B、Group_C
Element_2 Group_B、Group_C
Element_3 Group_A、Group_B、Group_D
Element_4 Group_A、Group_B、Group_D
Element_5 Group_C、Group_D

答案应该是:Element_1、Element_3 和 Element_4 匹配过滤器,显示的信息如下:

Group_A 有 3 个元素
Group_B 有 3 个元素
Group_C 有 1 个元素
Group_D 有 2 个元素

匹配过滤器

我怎么能把它放在 Core Data NSExpression、NSPredicate 等中?

谢谢。



更新

我想我找到了解决这个问题的两种方法。


选项1

此选项使用“组名称过滤器”建立一个 NSArray 并返回所有组,其元素数量与条件匹配,即使它为零(没有元素匹配)

有两个实体,“Grp”和“Elem”,它们之间存在一对多关系。

NSError *error = nil;

// Properties to be fetched
NSPropertyDescription *namePropDesc = [[[[self.moModel entitiesByName] objectForKey:@"Grp"] propertiesByName] objectForKey:@"name"];

// Variable group filter
NSArray *grpFilter = [NSArray arrayWithObjects:@"group_A", @"group_B", nil];

// Expression for counting elements
NSExpressionDescription *countExprDesc = [[NSExpressionDescription alloc] init];
[countExprDesc setExpression:[NSExpression expressionWithFormat:@"SUBQUERY(elems,$elem, SUBQUERY($elem.grps, $grp, $grp.name in %@).@count==%d).@count", grpFilter, grpFilter.count]];
[countExprDesc setExpressionResultType:NSInteger32AttributeType];
[countExprDesc setName:@"elementCount"];

// Create data fetching and set its properties
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Grp"];
[request setResultType:NSDictionaryResultType];
[request setPropertiesToFetch:[NSArray arrayWithObjects:namePropDesc,countExprDesc, nil]];

NSArray *results = [self.moContext executeFetchRequest:request error:&error];
NSLog(@"results = %@"results);


选项 2

此选项使用“组的名称过滤器”建立一个 NSArray,并返回所有组的元素数量与条件匹配,而没有那些没有任何元素的组。

在本例中,我创建了三个实体,Grp、Elem 和 RGE。将 RGE 作为中间实体,与其他两个实体保持一对多关系。如果需要,此选项允许在组元素关联(创建日期等)中放置一些额外信息。Grp 和 Elem 彼此之间没有关系。

注意:事实上,我需要在 RGE 实体中创建一个“常规”字段(名称)来应用 @count 函数。如果使用“多对多关系字段”,则无法正确计数。

NSError *error = nil;


// Variable group filter
NSArray *grpFilter = [NSArray arrayWithObjects:@"group_A", @"group_B", nil];

// Create variable predicate string from "group's names filter"
NSMutableString *predicateStr = [[NSMutableString alloc] init];
for(int n=0;n<grpFilter.count;n++) {
    if(n>0) {
        [predicateStr appendString:@" AND "];
    }
    [predicateStr appendString:@"(ANY elem.rges.grp.name=%@)"];
}

// Filter to be applied
NSPredicate *filterQuery = [NSPredicate predicateWithFormat:predicateStr argumentArray:grpFilter];

// Expression for counting elements
NSExpressionDescription *countExprDesc = [[NSExpressionDescription alloc] init];
[countExprDesc setExpression:[NSExpression expressionWithFormat:@"name.@count"]];
[countExprDesc setExpressionResultType:NSInteger64AttributeType];
[countExprDesc setName:@"count"];

// Expression for grouping JUST by the group's name
NSExpressionDescription *grpNameExprDesc = [[NSExpressionDescription alloc] init];
[grpNameExprDesc setExpression:[NSExpression expressionWithFormat:@"grp.name"]];
[grpNameExprDesc setExpressionResultType:NSStringAttributeType];
[grpNameExprDesc setName:@"grpName"];

// THIS COULD JUST BE an NSPropertyDescription if you want the WHOLE "grp":
NSPropertyDescription *grpPropDesc = [[[[self.moModel entitiesByName] objectForKey:@"RGE"] propertiesByName] objectForKey:@"grp"];

// Create data fetching and set its properties
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"RGE"];
[request setResultType:NSDictionaryResultType];
[request setPropertiesToGroupBy:[NSArray arrayWithObjects: grpNameExprDesc, nil]];
[request setPropertiesToFetch:[NSArray arrayWithObjects:grpNameExprDesc, countExprDesc, nil]];
[request setPredicate:filterQuery];


NSArray *results = [self.moContext executeFetchRequest:request error:&error];
NSLog(@"results = %@",results);
4

2 回答 2

0

我获取了所有组,并为显示做了以下操作:

Group *gr = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSSet *filtered = [NSSet set];
if ([gr.name isEqualToString:@"GroupA"]) {
   filtered = [gr.elements filteredSetUsingPredicate:
      [NSPredicate predicateWithFormat:@"any groups.name == %@", @"GroupB"]];
}
else if ([gr.name isEqualToString:@"GroupB"]) {
   filtered = [gr.elements filteredSetUsingPredicate:
      [NSPredicate predicateWithFormat:@"any groups.name == %@", @"GroupA"]];
}
else {
   filtered = [gr.elements filteredSetUsingPredicate:
      [NSPredicate predicateWithFormat:
        @"any groups.name == %@ && any groups.name == %@", 
        @"GroupA", @"GroupB"]];
}
cell.textLabel.text = 
   [NSString stringWithFormat:@"%@ has %d elements.", 
      gr.name, filtered.count] ;

这给出了正确的计数,如您的示例中所示。但是,如果有一个排除组,它仍然会列出 0 个元素。

于 2012-08-01T21:39:22.163 回答
0

我有一个类似的问题,我使用“选项 2”方法解决了它:将三个实体与多对多关系分组

问候。佩德罗文图拉。

于 2013-10-28T12:01:01.600 回答