Core Data を使用して次の問題を解決しようとしていますが、運がありません。
私のモデルには、Group と Element の 2 つのエンティティがあります。「name」属性と「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などに入れるにはどうすればよいですか?
ありがとう。
アップデート
これを解決する2つの方法を見つけたと思います。
オプション1
このオプションは、「グループ名フィルター」を使用して NSArray を確立し、条件に一致する要素の数を持つすべてのグループを返しますが、それはゼロです (一致する要素はありません)。
"Grp" と "Elem" の 2 つのエンティティがあり、それらの間には対多の関係があります。
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 の 3 つのエンティティを作成しました。RGE を他の 2 つの対多関係を維持する中間エンティティとして持つ。このオプションを使用すると、必要に応じて、グループ要素の関連付けに追加情報 (作成日など) を追加できます。Grp と Elem は相互に関係がありません。
注: 実際、@count 関数を適用するには、RGE エンティティに「通常の」フィールド (名前) を作成する必要がありました。「対多関係フィールド」を使用すると、正しくカウントされません。
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);