Polymorphicの実験(3) ==失敗== @Polymorphicと@OneToManyを組み合わせた再帰的構造
今回は、PolymorphicアノテーションとOneToManyアノテーションを組み合わせ、再帰的なデータ構造を表現してみました。
使用した題材は、ディレクトリ・ファイルの階層構造です。
ディレクトリの中にはサブディレクトリとファイルが複数含まれ、さらにサブディレクトリにも同様にサブサブディレクトリとファイルが含まれる再帰的な構造です。
結論としては、失敗でした。
ケース(1) -> 失敗
失敗の原因
ActiveObjectsのマイグレーション(DDL作成・実行)時に、各エンティティからインデックスを作成します。このインデックス作成時、対象のエンティティの上位エンティティについても同時にエンティティを作成します。
この上位エンティティの作成の際、上位エンティティがPolymorphicアノテーションを持っていても、その上位エンティティのインデックスを作成しようとします。しかし、Polymorphicアノテーションを持つエンティティに対応するテーブルは作成されないため、存在しないテーブルへのインデックスの作成となり、失敗してしまします。
ソースファイル(一部)
// 1.マイグレーション manager.migrate( Directory.class, File.class );
SQLの発行された順序
// 1.マイグレーション CREATE TABLE directory ( id INTEGER AUTO_INCREMENT NOT NULL, name VARCHAR(255), parentID INTEGER, CONSTRAINT fk_directory_parentid FOREIGN KEY (parentID) REFERENCES directory(id), PRIMARY KEY(id) ) ENGINE=InnoDB CREATE INDEX index_directory_parentid ON directory(parentID) CREATE INDEX index_node_parentid ON node(parentID) // 失敗
ソースを改変してみた -> 成功???
ActiveObjectsのnet.java.ao.SchemaGeneratorクラスのparseIndexes()メソッドで、エンティティを解析してインデックスDDLを作成しています。
以下には、上位エンティティのインデックス作成箇所をあげています。
オリジナルのソース
private static DDLIndex[] parseIndexes(TableNameConverter nameConverter, FieldNameConverter fieldConverter, Class> clazz) { (略) for (Class superInterface : clazz.getInterfaces()) { if (!superInterface.equals(RawEntity.class)) { back.addAll(Arrays.asList(parseIndexes(nameConverter, fieldConverter, (Class>) superInterface))); } } (略) return back.toArray(new DDLIndex[back.size()]); }
この部分を以下のように書き換え、Polymorphicアノテーションをもつ上位エンティティについては、インデックスを作成しないようにしました。
書き換えたソース
private static DDLIndex[] parseIndexes(TableNameConverter nameConverter, FieldNameConverter fieldConverter, Class> clazz) { (略) for (Class superInterface : clazz.getInterfaces()) { iif (!superInterface.equals(RawEntity.class) && superInterface.getAnnotation(Polymorphic.class) == null ) { back.addAll(Arrays.asList(parseIndexes(nameConverter, fieldConverter, (Class>) superInterface))); } } (略) return back.toArray(new DDLIndex[back.size()]); }
書き換え後の実行結果
上記のケース(1)とケース(2)の両方について、書き換えたActiveObjectsを使用して実行してみました。ケース(1)は失敗、ケース(2)は成功となりました。
書き換え後のケース(1)の失敗について
あまりきちんと調べていませんが、Directory.getNodes()の実行時に、存在しないノードテーブルからSELECTしようとして、失敗しているようです。
感想
オリジナルのソースでは思った通りには動作しなかったわけですが、ActiveObjectsの理解に役立ちました。
今回の現象が仕様なのかバグなのかの判断はまだつかないのですが、もしバグならバグフィックスを送ると改善されるのでしょうか?
そういうことはしたことがないので、わからんです。