ページ

2010年5月26日水曜日

CoreData - マイグレーション

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

モデルの修正
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 以上で利用できるようだ。