我一直在尝试使用 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);