woshidan's loose leaf

ぼんやり勉強しています

Realmのmigration中に「java.lang.IllegalArgumentException: Field already exists in 'Table': column」的なエラーで意味も無くはまった話

Realmで下記のようなmigrationのコードを書いていまして、よし、久しぶりにmigration前のバージョンからの移行処理を書こうか、と思ったところ、

public class Migration implements RealmMigration {
    @Override
    public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {
        RealmSchema schema = realm.getSchema();

        if (oldVersion == 0) {
            schema.create("Book")
                    .addField("name", String.class, FieldAttribute.REQUIRED) /* .addField("ownerLogin", String.class,  FieldAttribute.PRIMARY_KEY) */
                    .addField("price", int.class);

            oldVersion++;
        }
    }
}

Caused by: java.lang.IllegalArgumentException: Field already exists in 'Book': priceみたいなエラーが出て一向に進まないわけです。

うわー、何かふんじゃった? でもこのエラーしらべてもしらべても出て来ないんだけどって汗がね、めっちゃ出てくる。

というか、前のバージョンから結構でかい変更があるわけで、バージョンを切り替える1ビルド事に3分はかかりますので、一回試すだけで10分弱かかるんですね。

超あせるわけですよ。

もうね、鳥肌立ってくるというか。まあ、帰って熱はかったらがっつり風邪引いてたんですけど。

それで、復活してから見直してたらね、実際のコードは下記のような感じだったわけです。

public class Migration implements RealmMigration {
    @Override
    public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {
        RealmSchema schema = realm.getSchema();

        if (oldVersion == 0) {
            schema.create("Book")
                    .addField("name", String.class, FieldAttribute.REQUIRED) 
                    .addField("price", int.class)
                    .addField("price", int.class); // 2つめ!!!
            oldVersion++;
        }
    }
}

なるほど!! 来週も順調に仕事が進むね、やったねうぉしだん。

元気出していきましょう!!

なぜ、久しぶりに移行処理をする前に気づかなかったかといいますと、移行後の状態のコードでは、 Realmのインスタンスを下記のように「新しいSchemeバージョン」を指定して取得するようにしておりまして、 この場合、先ほどの oldVersion == 0 の処理は通ってないみたいなんですね。

RealmConfiguration newConfig = new RealmConfiguration.Builder(getApplicationContext())
                .schemaVersion(1)
                .build();

realm = Realm.getInstance(newConfig);

それで、ここからが悪いんですが、どうせなら一度のmigrationで追加した方が安心かな、と Realm migration怖い症候群により、oldVersion == 0 のところに後からさらに必要になった fieldの追加処理を書いていた、と。

でも、schemeバージョンが新しく指定されており、現行のrealmファイルと齟齬が無ければ、 migrationを走らせるように言ってくる例外は発生しないんですね。

要するに、移行後のschemeバージョンを指定して開発している間は、oldVersion == 0 のところのコードが走っていなかったので、追加分の間違いに気づくのが遅れたと。

なんか、少しだけ整理しきれていないのですが、こんな感じの気がします。

書いたタイミングから例外が投げられるタイミングが遠かったため、ただのタイポの類に何が起こったか、と思いました。怖っ!