ActiveObjectsのTIPS集

ActiveObjectsの操作に役に立つTIPSをどんどん追加していきます!!

「こんなことはできないの??」ということがあったら、調べて追記するのでコメントください。

TIPS一覧

  • エンティティ定義のTIPS
    • メソッドの実装を書く。
    • DBに保存できない型のsetterやgetterを作る。
  • エンティティ操作のTIPS
    • エンティティを追加する(1)
    • エンティティを追加する(2)
    • すべてのエンティティ取得する。
    • 条件にあてはまるすべてのエンティティ取得する。
    • すべてのエンティティ削除する。
    • 条件にあてはまるすべてのエンティティ削除する。
    • すべてのエンティティのプロパティを更新する。
    • 条件にあてはまるすべてのエンティティのプロパティを更新する。

■エンティティ定義のTIPS

●メソッドの実装を書く。

Implemantationアノテーションを使います。
エンティティのメソッドの実装が必要な場合、エンティティとは別に実装クラスを作成します。Implementationアノテーションでエンティティに対応する実装クラスを指定します。
以下は、Wikiクラスのredirectメソッドの実装をWikiImplクラスに書いた例です。

// エンティティ
@Implementation( WikiImpl.class );
public interface Wiki extends Entity {
        // 独自実装なし
    public void setFrontPage( String frontPage );
        public String getFrontPage();

        // 独自実装あり - 実装クラスのメソッドが呼び出されます。
	public void redirect( String page );
}
// 実装クラス
public class WikiImpl {
	
	private Wiki wiki;

	// コンストラクタ。引数にエンティティが渡されます。
	public WikiImpl( Wiki wiki ) {
		this.wiki = wiki;
	}
	
	// 実装メソッド
	public void redirect( String page ) {
		try {
			response.sendRedirect( createPageUrl( page ) );
		} catch ( IOException e ) {
			throw new RuntimeException( "redirect()", e );
		}
	}
}

Wikiエンティティのredirect()メソッドを呼び出すと、WikiImplクラスに書かれているredirect()メソッドのコードが実行されます。

●DBに保存できない型のsetterやgetterを作る。

を組み合わせます。
以下は、エンティティがPlugin型のsetterとgetterを持つ例です。Pluginは僕が独自に作ったクラスなので、DBに保存することはできません。

// エンティティ
@Implementation( PluginInfoImpl.class )
public interface PluginInfo extends Entity {
        @Ignore
        void setPlugin( Plugin plugin );
        Plugin getPlugin();
}

// エンティティの独自の実装
public class PluginInfoImpl {
        private Plugin plugin;
        public void setPlugin( Plugin plugin ) {
                this.plugin = plugin;
        }
        public Plugin getPlugin() {
                return plugin;
        }
}

まず、Implementationアノテーションを使って、setterやgetterの独自の実装を書きます。もし独自の実装を書かなければ、setPlugin()を呼び出したときに、「Unrecognized type: Plugin」というエラーが発生します。ActiveObjectsがPlugin型をDBの適切な型に変換できないためです。
さらに、Ignoreアノテーションを使って、マイグレーション時にpluginカラムを作成しないようにします。setPluginとgetPluginのどちらにもIgnoreアノテーション指定しない場合、ActiveObjectsマイグレーション時にpluginカラムを作成しようとします。この場合も適切に型変換できないため「Unrecognized type: Plugin」というエラーが発生します。

■エンティティ操作のTIPS

エンティティ操作のTIPSでは、PluginInfoというエンティティを使って説明します。このエンティティには以下の5つのフィールドがあります。

フィールド名 概要 備考
action プラグインの名前 ユニークな値
className プラグインのクラス名 -
type プラグインの種類 -
format プラグインの出力する書式 -
plugin プラグインインスタンスを取得する DBテーブルにカラムを作成しない。また、実装を独自に定義する

以下が実際のソースコードです。

// エンティティ
import net.java.ao.Entity;
import net.java.ao.Implementation;
import net.java.ao.schema.Unique;
import net.java.ao.schema.Ignore;

@Implementation( PluginInfoImpl.class )
public interface PluginInfo extends Entity {
        @Unique
        void setAction( String action );
        String getAction();

        void setClassName( String className );
        String getClassName();

        void setType( String type );
        String getType();

        void setFormat( String format );
        String getFormat();

        @Ignore
        Plugin getPlugin();
}

// 独自の実装
public class PluginInfoImpl {
        private PluginInfo info;

        public PluginInfoImpl( PluginInfo info ) {
                this.info = info;
        }

        public Plugin getPlugin() {
                try {
                        String className = info.getClassName();
                        Plugin bak = Class.forName( className ).asSubclass( Plugin.class ).newInstance();
                        return bak;
                } catch ( Exception e ) {
                        throw new RuntimeException( e );
                }
        }
}

mysqlの場合、PluginInfoエンティティのテーブルpluginInfoは以下のようになります。

mysql> desc pluginInfo;
+-----------+--------------+------+-----+---------+----------------+
| Field     | Type         | Null | Key | Default | Extra          |
+-----------+--------------+------+-----+---------+----------------+
| id        | int(11)      | NO   | PRI | NULL    | auto_increment |
| className | varchar(255) | YES  |     | NULL    |                |
| type      | varchar(255) | YES  |     | NULL    |                |
| format    | varchar(255) | YES  |     | NULL    |                |
| action    | varchar(255) | NO   | UNI | NULL    |                |
+-----------+--------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
●エンティティを追加する(1)

EntityManager#createメソッドを使います。
EntityManager#create()の引数として、エンティティのクラスと作成時に設定したいプロパティの値を指定します。プロパティの値はDBParamクラスを使って、new DBParam( "プロパティ名", 値 )の形で指定できます。
例1
以下は、新しいPluginInfoを作成し、actionに「NEW」を設定します。

EntityManager manager = ...;
manager.create( PluginInfo.class, new DBParam( "action", "NEW" ) );

mysqlのpluginInfoテーブルは以下のようになります。

mysql> select * from pluginInfo;
+----+-----------+------+--------+--------+
| id | className | type | format | action |
+----+-----------+------+--------+--------+
|  4 | NULL      | NULL | NULL   | NEW    |
+----+-----------+------+--------+--------+
3 rows in set (0.01 sec)

例2
以下は、新しいPluginInfoを作成し、actionに「NEW」を、classNameに「NewPage」を設定します。

EntityManager manager = ...;
manager.create( PluginInfo.class, new DBParam( "action", "NEW" ), new DBParam( "className", "NewPage" ) );

mysqlのpluginInfoテーブルは以下のようになります。

mysql> select * from pluginInfo;
+----+-----------+------+--------+--------+
| id | className | type | format | action |
+----+-----------+------+--------+--------+
|  4 | NewPage   | NULL | NULL   | NEW    |
+----+-----------+------+--------+--------+
3 rows in set (0.01 sec)

UNIQUEアノテーションが設定されたプロパティの値は、必ずEntityManager#create()の引数に指定しなければなりません。上の例では、setAction()がUNIQUEアノテーションを持っているので、actionを必ず指定する必要があります。もし、actionの値を指定しなければ、「Field 'action' doesn't have a default value」というエラーが発生します。
また、UNIQUEでないプロパティに対し、EntityManager#create()で値を設定しなかった場合、テーブルにはNULLが設定されます。

●エンティティを追加する(2)
  • EntityManager#create()メソッド
  • Entity#set〜()メソッド
  • Entity#save()メソッド

を使います。
createメソッドでエンティティを作成した後、エンティティのsetterでそれれぞれのプロパティの値を設定します。最後にエンティティのsave()メソッドを呼び出して、エンティティに設定した値がDBのテーブルに保存します。

EntityManager manager = ...;
PluginInfo info = manager.create( PluginInfo.class, new DBParam( "action", "NEW" ) );
info.setClassName( "NewPage" );
info.setType( "inline" );
info.setFormat( "html" );
info.save();

mysqlのpluginInfoテーブルは以下のようになります。

mysql> select * from pluginInfo;
+----+-----------+--------+--------+--------+
| id | className | type   | format | action |
+----+-----------+--------+--------+--------+
|  7 | NewPage   | inline | html   | NEW    |
+----+-----------+--------+--------+--------+
1 row in set (0.00 sec)

save()メソッドの呼び出しはうっかり忘れがちなので、注意が必要です。save()メソッドを呼び出さないとエンティティに設定した値はDBのテーブルに反映されません。
この場合も、UNIQUEアノテーションの設定されたプロパティの値は必ずcreate()メソッドで指定しなければなりません。

●すべてのエンティティ取得する。

EntityManger#find()メソッドを使います。
EntityManager#find()メソッドの引数には、取得するエンティティのクラスを指定します。結果はエンティティの配列として取得できます。
以下は、すべてのPluginInfoエンティティの内容を表示する例です。

EntityManager manager = ...;
for ( PluginInfo info : manager.find( PluginInfo.class ) ) {
       // エンティティの内容を画面に表示する。
       System.out.println( "action: " + info.getAction() + ", className: " + info.getClassName() );
}
●条件にあてはまるすべてのエンティティ取得する。
  • EntityManger#find()メソッド
  • Queryクラス

を組み合わせます。
EntityManager#find()で検索条件を指定することができます。二番目の引数として、検索条件を表すQueryのインスタンスを渡します。
以下は、actionが「NEW」であるPluginInfoエンティティの内容を表示する例です。

EntityManager manager = ...;
for ( PluginInfo info : manager.find( PluginInfo.class, Query.select().where( "action = ?", "NEW" ) ) ) {
       // エンティティの内容を画面に表示する。
       System.out.println( "action: " + info.getAction() + ", className: " + info.getClassName() );
}
go
●すべてのエンティティ削除する。
  • EntityManger#find()メソッド
  • EntityManger#delete()メソッド

を組み合わせます。
まず、find()メソッドですべてのエンティティを取得します。その後、EntityManager#delete()にそれぞれのエンティティを渡して削除を行います。

for ( PluginInfo info: manager.find( PluginInfo.class ) ) {
	manager.delete( info );
}

あるいは、以下でも同様に削除できます。

manager.delete( manager.find( PluginInfo.class ) );
●条件にあてはまるすべてのエンティティ削除する。
  • EntityManger#find()メソッド
  • Queryクラス
  • EntityManger#delete()メソッド

を組み合わせます。
まず、find()メソッドで条件にあてはまるエンティティを取得します。このとき、検索条件を指定するためにfind()メソッドにQueryのインスタンスを渡します。その後、EntityManager#delete()にそれぞれのエンティティを渡して削除を行います。
以下は、actionが「NEW」であるPluginInfoエンティティを削除する例です。

for ( PluginInfo info: manager.find( PluginInfo.class, Query.select().where( "action = ?", "NEW" ) ) ) {
	manager.delete( info );
}

あるいは、以下でも同様に削除できます。

manager.delete( manager.find( PluginInfo.class, Query.select().where( "action = ?", "NEW" ) ) );

削除前のテーブルが以下の場合、

mysql> select * from pluginInfo;
+----+-----------+--------+--------+--------+
| id | className | type   | format | action |
+----+-----------+--------+--------+--------+
|  1 | NewPage   | inline | html   | NEW    |
|  2 | EditPage  | inline | html   | EDIT   |
|  3 | ShowPage  | inline | html   |        |
+----+-----------+--------+--------+--------+
3 rows in set (0.00 sec)

削除後のテーブルは以下になります。

mysql> select * from pluginInfo;
+----+-----------+--------+--------+--------+
| id | className | type   | format | action |
+----+-----------+--------+--------+--------+
|  2 | EditPage  | inline | html   | EDIT   |
|  3 | ShowPage  | inline | html   |        |
+----+-----------+--------+--------+--------+
2 rows in set (0.00 sec)
●すべてのエンティティのプロパティを更新する。
  • EntityManger#find()メソッド
  • Entity#set〜()メソッド
  • Entity#save()メソッド

を組み合わせます。
まず、find()メソッドですべてのエンティティを取得します。その後、それぞれのエンティティのsetterを呼び出して、プロパティを更新します。さらに、それぞれのエンティティのsave()を呼んで、更新結果をDBのテーブルに保存します。

for ( PluginInfo info: manager.find( PluginInfo.class ) ) {
	// formatプロパティを「wiki」に更新する。
	info.setFormat( "wiki" );
	// 更新結果を保存する。
	info.save();
}

更新前のテーブルが以下の場合、

mysql> select * from pluginInfo;
+----+-----------+--------+--------+--------+
| id | className | type   | format | action |
+----+-----------+--------+--------+--------+
|  1 | NewPage   | inline | html   | NEW    |
|  2 | EditPage  | inline | html   | EDIT   |
|  3 | ShowPage  | inline | html   |        |
+----+-----------+--------+--------+--------+
3 rows in set (0.00 sec)

更新後のテーブルは以下になります。全ての行のformat列が更新されています。

mysql> select * from pluginInfo;
+----+-----------+--------+--------+--------+
| id | className | type   | format | action |
+----+-----------+--------+--------+--------+
|  1 | NewPage   | inline | wiki   | NEW    |
|  2 | EditPage  | inline | wiki   | EDIT   |
|  3 | ShowPage  | inline | wiki   |        |
+----+-----------+--------+--------+--------+
3 rows in set (0.00 sec)
●条件にあてはまるすべてのエンティティのプロパティを更新する。
  • EntityManger#find()メソッド
  • Queryクラス
  • Entity#set〜()メソッド
  • Entity#save()メソッド

を組み合わせます。
まず、find()メソッドで条件にあてはまるすべてのエンティティを取得します。このとき、検索条件を指定するためにfind()メソッドにQueryのインスタンスを渡します。その後、それぞれのエンティティのsetterを呼び出して、プロパティを更新します。さらに、それぞれのエンティティのsave()を呼んで、更新結果をDBのテーブルに保存します。

以下は、classNameが「ShowPage」であるPluginInfoエンティティをのactionプロパティを「SHOW」に更新する例です。

for ( PluginInfo info: manager.find( PluginInfo.class, Query.select().where( "className = ?", "ShowPage" ) ) ) {
	// actionプロパティを「SHOW」に更新する。
	info.setAction( "SHOW" );
	// 更新結果を保存する。
	info.save();
}

更新前のテーブルが以下の場合、

mysql> select * from pluginInfo;
+----+-----------+--------+--------+--------+
| id | className | type   | format | action |
+----+-----------+--------+--------+--------+
|  1 | NewPage   | inline | html   | NEW    |
|  2 | EditPage  | inline | html   | EDIT   |
|  3 | ShowPage  | inline | html   |        |
+----+-----------+--------+--------+--------+
3 rows in set (0.00 sec)

更新後のテーブルは以下になります。3行目のみaction列が更新されています。

mysql> select * from pluginInfo;
+----+-----------+--------+--------+--------+
| id | className | type   | format | action |
+----+-----------+--------+--------+--------+
|  1 | NewPage   | inline | html   | NEW    |
|  2 | EditPage  | inline | html   | EDIT   |
|  3 | ShowPage  | inline | html   | SHOW   |
+----+-----------+--------+--------+--------+
3 rows in set (0.00 sec)