CoreDataでうまいことMigrationする

CoreDataで定義した「モデル」を更新するには、Migrationを使います。モデルを「新しいバージョンを作成」して、これまでに公開したアプリとかで使ってる旧いモデルのデータを移行するMappingを定義します。CoreDataのMappingには2種類あり、自動でうまいことやってくれるやつと、手動で変換ルールを書くやつがあります。変換ルールを書くときには、このアトリビュートはこっちのアトリビュートになるよー!とマッピングに定義するか、MigrationPolicyというのを使ってどうやって変換するかをプログラムで書くことになります。

さて、Railsの世界観でMigrationを学んだ人には、ちょっと違いがあるので注意です。

一つ目は、マイグレーションはモデルの変更を書かないこと。まあこれはそういうもんだと思ってくれれば良いです。

二つ目は、普通にやると、マイグレーションは、各バージョンの差分に対して適用されるのではなく、現在使用中のバージョンから最新のバージョンに一気に適用されること。X,Y,Zとバージョンがあって、最新版がZ、現在使用中なのがXのとき、X→Y、Y→Zとマイグレーションされるのではなく、X→Zと一気にマイグレーションされます。

仮説「自動マイグレーションの推移律」:X→Y、Y→Zが両方とも、自動でできる場合は、X→Zも自動でできるような気がします。証明はしてないですが、直感的に。いや、リネームが怪しいかも。

で、これ、不便ですよね。身軽に開発を行いたいんです。バージョンはころころ変更して、旧いアトリビュートとか消したいですし、Just in Timeでアトリビュートは増やしていきたい。そうすると、必然的にバージョンは増えて、過去にリリースされた全てのバージョンから最新版へのマイグレーションを書くとか、アホなことはやりたくない。

で、うまいことやるプログラムを書きました。

https://github.com/soutaro/arelish

ここのUBCoreDataMigrationHelperを使います。

Mappingを手で定義してあるバージョン間は、Mappingを使います。Mappingは最も離れたやつを使うようになっています。上の自動でできるマイグレーションには推移律が成り立つ仮説から、複数の自動マイグレーションされるやつがあるときは中間をスキップするようになっています。

上手く動かすための仮定として、A,B,C,Dがあるとして、A→C、B→Dのような交差するMappingはないこととしています。また、モデルのバージョン名に仮定があります。Model→Model 2→Model 3のような名前で、バージョンが進んで行くことを仮定しています。