モデルの修正
CoreDataのマイグレーションを試してみた。通常モデルに修正を加えると、直前に作成したSQLiteDBは使えず実行時エラーが出る。この場合、SQLiteDBを一旦削除する必要がある。当然データの引き継ぎはできない。
エラーログ:
[16769:a0f] Error Domain=NSCocoaErrorDomain Code=134100 UserInfo=0x116760 "The managed object model version used to open the persistent store is incompatible with the one that was used to create the persistent store."
[16769:a0f] This NSPersistentStoreCoordinator has no persistent stores. It cannot perform a save operation.
CoreDataでのデータマイグレーション
CoreDataにはマイグレーションの仕組みが用意されていて、これを利用することができる。
Core Data Model Versioning and Data Migration Programming Guide: Introduction to Core Data Model Versioning and Data Migration Programming Guide
属性値の追加など簡単な変更については自動マイグレーションが使えるようだ。
Core Data Model Versioning and Data Migration Programming Guide: Lightweight Migration
自動マイグレーションは下記が参考になる。
Core Dataの自動マイグレーション | hippos-lab::blog
試してみよう。
自動マイグレーション
1. モデルバージョンを追加する。
CoreDataRelationship_DataModel 2.xcdatamodel が追加された。
2. モデルを変更する。
今回は新しいバージョンの方に属性 published (NSData)を追加する。
3. Mapping Model を作成する。
名前は map-01-02.xcmappingmodel としてみた。
ソース(旧)とデスティネーション(新)のモデルをそれぞれ指定する。
4. Mapping Model ファイルを開く。「差分を表示」を使うと新旧モデルの比較ができる。下図は published が追加されたことを表している。
5. 属性マッピングを設定する
published はオプションなのでそのままでも問題ないのだが、試しに created の値を使うようにしてみた。
6. マイグレーションコードを追加する。
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
[persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:url
options:options
error:&error];
options: にマイグレーション用オプションを追加する。
7. 現在のバージョンを設定する。
新バージョンを選択後にメニューから設定する。
チェックがつく。
8. 実行
エラーが出なくなった。SQLite の中をみてみる。
sqlite> .schema ZBLOGENTRY
CREATE TABLE ZBLOGENTRY ( Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER, Z_OPT INTEGER, ZPUBLISHED TIMESTAMP, ZCREATED TIMESTAMP, ZTITLE VARCHAR, ZCONTENT VARCHAR );
ZPUBLISHED が追加されている。データも ZCREATEDの値がコピーされているのが確認できた。
sqlite> select * from ZBLOGENTRY; 1|2|5|296460106.418831|296460106.418831|iPad 5/28発売|かくかくしかじか 2|2|8|296460106.418047|296460106.418047|CoreData のリレーションしっぷについて|かくかくしかじか
飛ばしバージョンアップ (1→3)
さらに続けてバージョン3を作る。その上で、バージョン1のデータがどうなるかをみてみよう。
まずバージョン3のモデルを作る。
BlogEntryへ visible(BOOL)を追加してみた。
Mappin Model を作る。ソースはバージョン2、デスティネーションはバージョン3にした。
新属性 visible には YES (==1)を当てた。
実行してみよう。まずはバージョン2→3の動作をみる。sqlite> .schema ZBLOGENTRY
CREATE TABLE ZBLOGENTRY ( Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER, Z_OPT INTEGER, ZVISIBLE INTEGER, ZPUBLISHED TIMESTAMP, ZCREATED TIMESTAMP, ZTITLE VARCHAR, ZCONTENT VARCHAR );
sqlite> select * from ZBLOGENTRY; 1|2|4|1|296460106.418831|296460106.418831|iPad 5/28発売|かくかくしかじか 2|2|6|1|296460106.418047|296460106.418047|CoreData のリレーションしっぷについて|かくかくしかじかvisibleが追加されているのが確認できた。
さて次はいよいよ1→3のマイグレーションを試みる。とっておいたバージョン1のSQLIteDBファイルをおいて、現在のモデルのバージョンを3として実行する。
結果はOK。
おお賢い。おそらく 1→2, 2→3 と自動的にマイグレーションを適用しているのだろう。
sqlite> .schema ZBLOGENTRY
CREATE TABLE ZBLOGENTRY ( Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER, Z_OPT INTEGER, ZVISIBLE INTEGER, ZPUBLISHED TIMESTAMP, ZCREATED TIMESTAMP, ZTITLE VARCHAR, ZCONTENT VARCHAR );
sqlite> select * from ZBLOGENTRY; 1|2|4|1|296460106.418831|296460106.418831|iPad 5/28発売|かくかくしかじか 2|2|6|1|296460106.418047|296460106.418047|CoreData のリレーションしっぷについて|かくかくしかじか
気がついた点
バックアップファイルが自動生成される
SQLite のDBファイルがマイグレーション直前にコピーされ、バックアップがとられるようだ。
CoreDataRelationship.db CoreDataRelationship~.db ←バックアップ
NSInferMappingModelAutomaticallyOption
-[NSPersistentStoreCoordinator addPersistentStoreWithType:configuration:URL:options:error:] で渡すオプション NSInferMappingModelAutomaticallyOption は Mac OS v10.6 以上なので、v10.5 では使えない。
調べたところ iPhone は 3.0 以上で利用できるようだ。