我有一个包含三个属性的实体:studyID
:string,s tudyName
:string和studyDate
:date。
我需要为搜索创建谓词,但用户可以选择输入所有三个属性的任何可能组合,例如一个搜索位于studyID
和studyDate
但不是studyName
,而下一个搜索位于studyID
。
如何根据用户决定搜索的属性组合动态创建谓词?
答案 0 :(得分:7)
您需要创建一个复合谓词,其最终形式取决于用户搜索的属性。
最干净的解决方案是使用NSExpression,NSComparisonPredicate和NSCompoundPredicate在代码中构建谓词。这样您就可以自定义每个搜索的谓词。
这样的事情:
-(NSPredicate *) predicateWithStudyID:(NSString *) aStudyID studyName:(NSString *) aStudyName date:(NSDate *) aDate{
NSPredicate *p;
NSMutableArray *preds=[[NSMutableArray alloc] initWithCapacity:1];
if (aDate != nil) {
NSExpression *dateKeyEx=[NSExpression expressionForKeyPath:@"studyDate"];
NSExpression *aDateEx=[NSExpression expressionForConstantValue:aDate];
NSPredicate *datePred=[NSComparisonPredicate predicateWithLeftExpression:dateKeyEx
rightExpression:aDateEx
modifier:NSDirectPredicateModifier
type:NSEqualToPredicateOperatorType
options:0];
[preds addObject:datePred];
}
if (![aStudyID isEqualToString:@""]) {
NSExpression *studyIDKeyEx=[NSExpression expressionForKeyPath:@"studyID"];
NSExpression *aStudyIDEx=[NSExpression expressionForConstantValue:aStudyID];
NSPredicate *studyIDPred=[NSComparisonPredicate predicateWithLeftExpression:studyIDKeyEx
rightExpression:aStudyIDEx
modifier:NSDirectPredicateModifier
type:NSLikePredicateOperatorType
options:NSCaseInsensitivePredicateOption];
[preds addObject:studyIDPred];
}
if (![aStudyName isEqualToString:@""]) {
NSExpression *studyNameKeyEx=[NSExpression expressionForKeyPath:@"studyName"];
NSExpression *aStudyNameEx=[NSExpression expressionForConstantValue:aStudyName];
NSPredicate *studyNamePred=[NSComparisonPredicate predicateWithLeftExpression:studyNameKeyEx
rightExpression:aStudyNameEx
modifier:NSDirectPredicateModifier
type:NSLikePredicateOperatorType
options:NSCaseInsensitivePredicateOption];
[preds addObject:studyNamePred];
}
p=[NSCompoundPredicate andPredicateWithSubpredicates:preds];
[preds release];
return p;
}
然后你会像这样使用它:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSDate *firstDate=[NSDate date];
NSDate *secondDate=[firstDate dateByAddingTimeInterval:60*60*24];
NSDate *thirdDate=[secondDate dateByAddingTimeInterval:60*60*24];
// I use an array of dictionaries for convenience but it works
// for managed objects just as well.
NSDictionary *d1=[NSDictionary dictionaryWithObjectsAndKeys:
@"abc123", @"studyID",
@"firstStudy", @"studyName",
firstDate, @"studyDate",
nil];
NSDictionary *d2=[NSDictionary dictionaryWithObjectsAndKeys:
@"abc456", @"studyID",
@"secondStudy", @"studyName",
secondDate, @"studyDate",
nil];
NSDictionary *d3=[NSDictionary dictionaryWithObjectsAndKeys:
@"abc789", @"studyID",
@"thirdStudy", @"studyName",
thirdDate, @"studyDate",
nil];
NSArray *a=[NSArray arrayWithObjects:d1,d2,d3, nil];
NSPredicate *p=[self predicateWithStudyID:@"" studyName:@"thirdStudy" date:thirdDate];
NSLog(@"p = %@",p);
NSArray *filtered=[a filteredArrayUsingPredicate:p];
NSLog(@"%@",filtered);
return YES;
}
请参阅Predicate Programming Guide: Creating Predicate Directly in Code
-(NSPredicate *) predicateWithStudyID:(NSString *) aStudyID studyName:(NSString *) aStudyName date:(NSDate *) aDate{
NSPredicate *p;
NSMutableArray *preds=[[NSMutableArray alloc] initWithCapacity:1];
if (aDate != nil) {
NSPredicate *datePred=[NSPredicate predicateWithFormat:@"studyDate==%@",aDate];
[preds addObject:datePred];
}
if (![aStudyID isEqualToString:@""]) {
NSPredicate *studyIDPred=[NSPredicate predicateWithFormat:@"studyID Like %@",aStudyID];
[preds addObject:studyIDPred];
}
if (![aStudyName isEqualToString:@""]) {
NSPredicate *studyNamePred=[NSPredicate predicateWithFormat:@"studyName Like %@",aStudyName];
[preds addObject:studyNamePred];
}
p=[NSCompoundPredicate andPredicateWithSubpredicates:preds];
[preds release];
return p;
}
答案 1 :(得分:0)
利用这个问题的灵感,我为连接管理器创建了自己的通用提取,以便于重用。使用字典我能够发送键/值对来动态生成适当的谓词并返回结果,而不必每次都担心其余的。我希望它有所帮助...
- (NSArray *)fetchObjects:(NSString *)entityName
Parameters:(NSMutableDictionary *)parameters
{
NSMutableArray *preds = [[NSMutableArray alloc] init];
NSPredicate *pred;
NSEnumerator *enumerator = [parameters keyEnumerator];
for(NSString *aKey in enumerator)
{
pred=[NSPredicate predicateWithFormat:@"%K = %@", aKey, [parameters objectForKey:aKey]];
[preds addObject:pred];
[Log LogTrace:[NSString stringWithFormat:@"Query - Entity: %@ Predicate: %@ = %@", entityName, aKey, [parameters objectForKey:aKey]]];
}
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity =
[NSEntityDescription entityForName:entityName
inManagedObjectContext:_managedObjectContext];
[request setEntity:entity];
NSPredicate *requestPreditace = [NSCompoundPredicate andPredicateWithSubpredicates:preds];
[request setPredicate:requestPreditace];
NSError *error;
NSArray *array = [_managedObjectContext executeFetchRequest:request error:&error];
[Log LogTrace:[NSString stringWithFormat:@"Results count: %d", [array count]]];
if (error)
[Log LogError:[NSString stringWithFormat:@"*** Core Data fetch ERROR: %@", [error localizedDescription]]];
return array;
}