CoreData でリレーションシップ(関連)を扱う必要が出てきたのでこれから調査していく。
※今回 MacOSX10.5で検証。
まずはこんなモデルを作ってみた。
BlogEntry.h
@interface BlogEntry : NSManagedObject
{
}
@property (retain) NSDate * created;
@property (retain) NSString * title;
@property (retain) NSString * content;
@property (retain) NSSet* tags;
@end
@interface BlogEntry (CoreDataGeneratedAccessors)
- (void)addTagsObject:(NSManagedObject *)value;
- (void)removeTagsObject:(NSManagedObject *)value;
- (void)addTags:(NSSet *)value;
- (void)removeTags:(NSSet *)value;
@end
Tag.h
@interface Tag : NSManagedObject
{
}
@property (retain) NSString * name;
@end
テストデータはプログラムで詰め込む。
- (void)addTestData
{
if ([self getCount]) {
return;
}
NSManagedObjectContext* moc = [self managedObjectContext];
Tag* tag1 = [NSEntityDescription insertNewObjectForEntityForName:@"Tag"
inManagedObjectContext:moc];
tag1.name = @"Mac";
Tag* tag2 = [NSEntityDescription insertNewObjectForEntityForName:@"Tag"
inManagedObjectContext:moc];
tag2.name = @"iPhone";
Tag* tag3 = [NSEntityDescription insertNewObjectForEntityForName:@"Tag"
inManagedObjectContext:moc];
tag3.name = @"iPad";
BlogEntry* blog1 = [NSEntityDescription insertNewObjectForEntityForName:@"BlogEntry"
inManagedObjectContext:moc];
blog1.title = @"CoreData のリレーションしっぷについて";
blog1.content = @"かくかくしかじか";
blog1.created = [NSDate date];
blog1.tags = [NSSet setWithObjects:tag1, tag2, tag3, nil];
BlogEntry* blog2 = [NSEntityDescription insertNewObjectForEntityForName:@"BlogEntry"
inManagedObjectContext:moc];
blog2.title = @"iPad 5/28発売";
blog2.content = @"かくかくしかじか";
blog2.created = [NSDate date];
blog2.tags = [NSSet setWithObjects:tag3, nil];
NSError* error = nil;
[moc save:&error];
if (error) {
NSLog(@"INSERT ERROR: %@", error);
} else {
NSLog(@"INSERTED");
}
}
これをフェッチしてみる。ログを追いやすい様に仕切りを入れてある。
- (void)fetchData
{
NSManagedObjectContext* moc = [self managedObjectContext];
NSFetchRequest* request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:@"BlogEntry"
inManagedObjectContext:managedObjectContext]];
NSError* error = nil;
NSLog(@"----- executeFetchRequest ------------------------------------------");
NSArray* list = [moc executeFetchRequest:request error:&error];
NSLog(@"----- listup tag ---------------------------------------------------");
for (BlogEntry* entry in list) {
for (Tag* tag in entry.tags) {
NSLog(@"*tag*: %@", tag.name);
}
}
[request release];
}
さて実行してみる。設定で実行SQLもログに出るようにしてある。
[13883:10b] CoreData: sql: pragma cache_size=1000
[13883:10b] CoreData: sql: SELECT Z_VERSION, Z_UUID, Z_PLIST FROM Z_METADATA
[13883:10b] CoreData: sql: SELECT COUNT(*) FROM ZBLOGENTRY t0
[13883:10b] CoreData: annotation: total count request execution time: 0.0022s for count of 2.
[13883:10b] ----- executeFetchRequest ------------------------------------------
[13883:10b] CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZTITLE, t0.ZCONTENT, t0.ZCREATED FROM ZBLOGENTRY t0
[13883:10b] CoreData: annotation: sql connection fetch time: 0.0013s
[13883:10b] CoreData: annotation: total fetch execution time: 0.0033s for 2 rows.
[13883:10b] ----- fetch tags ---------------------------------------------------
[13883:10b] CoreData: sql: SELECT 0, t0.Z_PK FROM ZTAG t0 WHERE t0.Z1TAGS = ?
[13883:10b] CoreData: annotation: sql connection fetch time: 0.0017s
[13883:10b] CoreData: annotation: total fetch execution time: 0.0034s for 2 rows.
[13883:10b] CoreData: annotation: to-many relationship fault "tags" for objectID 0x17bfe0
[13883:10b] CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZNAME, t0.Z1TAGS FROM ZTAG t0 WHERE t0.Z_PK = ?
[13883:10b] CoreData: annotation: sql connection fetch time: 0.0015s
[13883:10b] CoreData: annotation: total fetch execution time: 0.0037s for 1 rows.
[13883:10b] CoreData: annotation: fault fulfilled from database for : 0x17dd40
[13883:10b] ** iPhone
[13883:10b] CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZNAME, t0.Z1TAGS FROM ZTAG t0 WHERE t0.Z_PK = ?
[13883:10b] CoreData: annotation: sql connection fetch time: 0.0013s
[13883:10b] CoreData: annotation: total fetch execution time: 0.0023s for 1 rows.
[13883:10b] CoreData: annotation: fault fulfilled from database for : 0x17c5b0
[13883:10b] ** Mac
[13883:10b] CoreData: sql: SELECT 0, t0.Z_PK FROM ZTAG t0 WHERE t0.Z1TAGS = ?
[13883:10b] CoreData: annotation: sql connection fetch time: 0.0010s
[13883:10b] CoreData: annotation: total fetch execution time: 0.0020s for 1 rows.
[13883:10b] CoreData: annotation: to-many relationship fault "tags" for objectID 0x17bff0
[13883:10b] CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZNAME, t0.Z1TAGS FROM ZTAG t0 WHERE t0.Z_PK = ?
[13883:10b] CoreData: annotation: sql connection fetch time: 0.0012s
[13883:10b] CoreData: annotation: total fetch execution time: 0.0116s for 1 rows.
[13883:10b] CoreData: annotation: fault fulfilled from database for : 0x17d000
[13883:10b] ** iPad
わかりずらいが、まとめると次のようになる。
- BlogEntry を取得した段階では Tagは取得されない(fault状態)
- Tag への参照が発生した段階で、SELECTが発行される
なるほど。データのフェッチは必要最低限になるようだ。これはいい。
ソースコード:
CoreDataRelationship at 2010-05-17 from xcatsan's SampleCode - GitHub
(続く)