こんにちわ。ゆんぼうです。
前回の続きで、今回はCoreDataを用いて、データベース検索を行います。
今回の開発環境は以下の通りです。
・OS X v10.9.3
・Xcode v5.1.1
前回作成したDAOクラス SampleEntityDAO に
名前と年齢で検索を行うインスタンスメソッドを追加します。
- (NSArray *)getSampleEntityItemList:(NSString *)name age:(NSNumber *)age
{
AppDelegate *appDeletage = [[UIApplication sharedApplication]delegate];
NSManagedObjectContext *managedObjectContext = [appDeletage managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]init];
NSEntityDescription *entityDes = [NSEntityDescription entityForName:@"SampleEntity" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entityDes];
if(nil != name || nil != age){
NSMutableArray *predicateCommandArray = [[NSMutableArray alloc]init];
if(nil != name){
NSString *nameWord = [NSString stringWithFormat:@"*%@*",name];
NSPredicate *predicate = [NSComparisonPredicate predicateWithLeftExpression:[NSExpression expressionForKeyPath:@"name"] rightExpression:[NSExpression expressionForConstantValue:nameWord] modifier:NSDirectPredicateModifier type:NSLikePredicateOperatorType options:0];
[predicateCommandArray addObject:predicate];
}
if(nil != age){
NSString *predicateCommand = [NSString stringWithFormat:@"(age = %@)",age];
NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateCommand];
[predicateCommandArray addObject:predicate];
}
if(nil != predicateCommandArray){
NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:predicateCommandArray];
[fetchRequest setPredicate:predicate];
}
}
NSSortDescriptor *sortDes = [[NSSortDescriptor alloc]initWithKey:@"age" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc]initWithObjects:sortDes, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSError *error = nil;
NSArray *itemList = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
if(nil != error){
NSLog(@"SampleEntityDAO#getSampleEntityItemList error %@, %@", error, [error userInfo]);
}
return itemList;
}
検索条件は、NSPredicateクラスを使用します。
複数ある場合は、NSPredicate オブジェクトを配列にして、
NSCompoundPredicate クラスを用いて条件を纏めます。
ここでは、名前と年齢の検索条件の NSPredicate オブジェクトを作成して、
andPredicateWithSubpredicates クラスメソッドを用いて、AND条件で纏めています。
まず、年齢の検索条件を見てみると
文字列の条件式 「age = %@」を predicateWithFormat クラスメソッドで
NSPredicate オブジェクトを作成します。
次に、名前の検索条件を見てみると、
下記のように文字列の条件式「name LIKE '*%@*'」で実装することもできますが、
ここでは実装しておりません。
NSString *predicateCommand = [NSString stringWithFormat:@"name LIKE '*%@*'",name];
なぜならば、悪意を持ったユーザーがいて、
この名前の値にSQL文を指定すると、そのSQL文が実行されてしまいます。
このSQL文を利用して、データベースを不正に操作する攻撃をSQL Injectionといいます。
SQL Injection を回避するため、
「name LIKE '*%@*'」のような文字列で条件式を作成するのではなく、
NSComparisonPredicate クラスを用いて、条件式を作成します。
この検索条件の呼び出し側を実装します。
1回目は、「お」を含む名前でデータベースを検索します。
2回目は、年齢が29でデータベースを検索します。
3回目は、「さ」を含む名前、かつ年齢が29でデータベースを検索します。
NSLog(@"---------------------------------------");
NSArray *item2List = [dao getSampleEntityItemList:@"お" age:nil];
for(SampleEntity *item in item2List) {
NSLog(@"name:%@, age:%@",item.name, item.age);
}
NSLog(@"---------------------------------------");
NSArray *item3List = [dao getSampleEntityItemList:nil age:[NSNumber numberWithInt:29]];
for(SampleEntity *item in item3List) {
NSLog(@"name:%@, age:%@",item.name, item.age);
}
NSLog(@"---------------------------------------");
NSArray *item4List = [dao getSampleEntityItemList:@"さ" age:[NSNumber numberWithInt:29]];
for(SampleEntity *item in item3List) {
NSLog(@"name:%@, age:%@",item.name, item.age);
}
NSLog(@"---------------------------------------");
実行すると下記の内容になります。
出力結果
---------------------------------------
name:しおぼう, age:40
---------------------------------------
name:あさぼう, age:29
---------------------------------------
name:あさぼう, age:29
---------------------------------------
以上です。