Master -
Yucchi
Since - 2012/05/05
Java Persistence API で遊ぶ - 2 -
Java Persistence API で遊ぶ -1-の続きです。
今回は NetBeans6.0RC1 によって自動生成されるエンティティクラスについて調べてみます。
開発環境は
OS Windows Vista Ultimate 64bit
JDK6u3
NetBeans IDE 6.0 RC1
MySQL 5.0.45 (Community 版)
です。
利用するデータベースはこのような構造です。
各テーブルは下記のようになってます。
talent テーブル
DROP TABLE IF EXISTS `talentdb`.`talent`; CREATE TABLE `talentdb`.`talent` ( `TALENT_ID` int(10) unsigned NOT NULL auto_increment, `TALENT_NAME` varchar(45) NOT NULL, `OFFICE_ID` int(10) unsigned default NULL, `ADDRESS_ID` int(10) unsigned default NULL, `HOBBY_ID` int(10) unsigned NOT NULL, `HEIGHT` int(10) unsigned default NULL, `BUST` int(10) unsigned default NULL, `WAIST` int(10) unsigned default NULL, `HIPS` int(10) unsigned default NULL, `BIRTHDAY` date default NULL, PRIMARY KEY (`TALENT_ID`), KEY `FK_talent_1` (`OFFICE_ID`), KEY `FK_talent_2` (`ADDRESS_ID`), KEY `FK_talent_3` (`HOBBY_ID`), CONSTRAINT `FK_talent_1` FOREIGN KEY (`OFFICE_ID`) REFERENCES `office` (`OFFICE_ID`) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT `FK_talent_2` FOREIGN KEY (`ADDRESS_ID`) REFERENCES `address` (`ADDRESS_ID`) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT `FK_talent_3` FOREIGN KEY (`HOBBY_ID`) REFERENCES `hobby` (`HOBBY_ID`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=sjis;
office テーブル
DROP TABLE IF EXISTS `talentdb`.`office`; CREATE TABLE `talentdb`.`office` ( `OFFICE_ID` int(10) unsigned NOT NULL auto_increment, `OFFICE_NAME` varchar(100) NOT NULL, `ADDRESS` varchar(100) NOT NULL, PRIMARY KEY (`OFFICE_ID`) ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=sjis;
hobby テーブル
DROP TABLE IF EXISTS `talentdb`.`hobby`; CREATE TABLE `talentdb`.`hobby` ( `HOBBY_ID` int(10) unsigned NOT NULL auto_increment, `HOBBY_NAME_1` varchar(45) default NULL, `HOBBY_NAME_2` varchar(45) default NULL, `HOBBY_NAME_3` varchar(45) default NULL, PRIMARY KEY (`HOBBY_ID`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=sjis;
project テーブル
DROP TABLE IF EXISTS `talentdb`.`project`; CREATE TABLE `talentdb`.`project` ( `PROJECT_ID` int(10) unsigned NOT NULL auto_increment, `PROJECT_NAME` varchar(100) default NULL, `PLATFORM` varchar(100) default NULL, PRIMARY KEY (`PROJECT_ID`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=sjis;
talent_project テーブル
DROP TABLE IF EXISTS `talentdb`.`talent_project`; CREATE TABLE `talentdb`.`talent_project` ( `TALENT_ID` int(10) unsigned NOT NULL, `PROJECT_ID` int(10) unsigned NOT NULL, PRIMARY KEY (`TALENT_ID`,`PROJECT_ID`), KEY `FK_TALENT_PROJECT_2` (`PROJECT_ID`), CONSTRAINT `FK_TALENT_PROJECT_1` FOREIGN KEY (`TALENT_ID`) REFERENCES `talent` (`TALENT_ID`) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT `FK_TALENT_PROJECT_2` FOREIGN KEY (`PROJECT_ID`) REFERENCES `project` (`PROJECT_ID`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=sjis;
genre テーブル
DROP TABLE IF EXISTS `talentdb`.`genre`; CREATE TABLE `talentdb`.`genre` ( `GENRE_ID` int(10) unsigned NOT NULL auto_increment, `GENRE_NAME_1` varchar(100) NOT NULL, `GENRE_NAME_2` varchar(100) default NULL, `GENRE_NAME_3` varchar(100) default NULL, PRIMARY KEY (`GENRE_ID`) ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=sjis;
talent_genre テーブル
DROP TABLE IF EXISTS `talentdb`.`talent_genre`; CREATE TABLE `talentdb`.`talent_genre` ( `TALENT_ID` int(10) unsigned NOT NULL auto_increment, `GENRE_ID` int(10) unsigned NOT NULL, PRIMARY KEY (`TALENT_ID`,`GENRE_ID`), KEY `FK_TALENT_GENRE_1` (`GENRE_ID`), CONSTRAINT `FK_TALENT_GENRE_1` FOREIGN KEY (`GENRE_ID`) REFERENCES `genre` (`GENRE_ID`) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT `FK_TALENT_GENRE_2` FOREIGN KEY (`TALENT_ID`) REFERENCES `talent` (`TALENT_ID`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=sjis;
email テーブル
DROP TABLE IF EXISTS `talentdb`.`email`; CREATE TABLE `talentdb`.`email` ( `EMAIL_ID` int(10) unsigned NOT NULL auto_increment, `HOLDER_ID` int(10) unsigned default NULL, `EMAIL_ADDRESS` varchar(100) NOT NULL, PRIMARY KEY (`EMAIL_ID`), KEY `FK_email_1` (`HOLDER_ID`), CONSTRAINT `FK_email_1` FOREIGN KEY (`HOLDER_ID`) REFERENCES `talent_email` (`HOLDER_ID`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=sjis;
talent_email テーブル
DROP TABLE IF EXISTS `talentdb`.`talent_email`; CREATE TABLE `talentdb`.`talent_email` ( `HOLDER_ID` int(10) unsigned NOT NULL, `EMAIL_ID` int(10) unsigned NOT NULL, PRIMARY KEY (`HOLDER_ID`,`EMAIL_ID`), KEY `FK_TALENT_EMAIL_1` (`EMAIL_ID`), CONSTRAINT `FK_TALENT_EMAIL_1` FOREIGN KEY (`EMAIL_ID`) REFERENCES `email` (`EMAIL_ID`) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT `FK_TALENT_EMAIL_2` FOREIGN KEY (`HOLDER_ID`) REFERENCES `talent` (`TALENT_ID`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=sjis;
address テーブル
DROP TABLE IF EXISTS `talentdb`.`address`; CREATE TABLE `talentdb`.`address` ( `ADDRESS_ID` int(10) unsigned NOT NULL auto_increment, `PREFECTURE` varchar(45) default NULL, `CITY` varchar(45) default NULL, PRIMARY KEY (`ADDRESS_ID`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=sjis;
phone テーブル
DROP TABLE IF EXISTS `talentdb`.`phone`; CREATE TABLE `talentdb`.`phone` ( `HOLDER_ID` int(10) unsigned NOT NULL auto_increment, `PHONE_NUMBER` varchar(45) default NULL, PRIMARY KEY (`HOLDER_ID`), CONSTRAINT `FK_PHONE_1` FOREIGN KEY (`HOLDER_ID`) REFERENCES `talent` (`TALENT_ID`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=sjis;
以上のようなテーブルを使用します。
それでは新規プロジェクトをつくりましょう。
[ File ] → [ New Project... ] で新規プロジェクトを作ります。
新規プロジェクトウィンドウが表示されます。
[ Java ] → [ Java Application ] を選択し [ Next > ] ボタンを押します。
次のステップでは下記のようにプロジェクト名、ロケーションなどを設定します。
そして、[ Finish ] ボタンを押します。
データベースからエンティティクラスを作ります。
[ データベース接続 ] を選択し、利用するデータベースに接続します。
利用可能な表から先ほどのテーブルを選択し追加します。
リレーションシップがとられている表は自動的に選択されてしまします。
エンティティクラスの設定をします。
今回は [ 持続フィールド用の NamedQuery 注釈を生成 ] のチェックを外しておきます。
[ 持続性ユニットを生成... ] ボタンを押します。
持続性ユニット名をつけて [ 作成 ] ボタンを押します。
設定を確認して [ 完了 ] ボタンを押します。
下図のようなエンティティクラスが作成されたことが確認できます。
talent テーブルから作成されたエンティティクラスのソースコードの一部です。
それでは talent テーブルから作成されたエンティティクラスと各テーブルから作成されたエンティティクラスの関係を確認してみます。
talent テーブルと office テーブルから生成されたエンティティクラスの確認
Talent.java のソースコードの一部
Office.java のソースコードの一部
Talent.java が主で ManyToOne になっているのが解ります。
Office.java は従で OneToMany です。
ちゃんとリレーションシップがとれてます。
それではよく似た構造の hobby テーブルから作成されたエンティティクラスとの関係を見てみましょう。
Talent.java
Hobby.java
Talent.java が主で ManyToOne になってます。
しかし、Hobby.java は従で OneToMany になってますがカスケード戦略がとられてます。
これは talent テーブルの HOBBY_ID ( 外部キー ) が NOT NULL になっているからです。
このようなことを解析し、エンティティクラスを自動生成する機能は素晴らしいですね。
次は project テーブルから生成されたエンティティクラスを確認します。
Talent.java
Project.java
Talent.java が主で ManyToMany で生成されてます。
もちろん、ジョインテーブルを解析して @JoinTable アノテーションも使われています。
Project.java は従で ManyToMany で生成されてます。
project テーブルの PROJECT_NAME , PLATFORM のデフォルト値が null だからでしょう。
では、同じようなテーブル構造の genre テーブルから生成されたエンティティクラスを確認します。
Talent.java
Genre.java
Talent.java が従で ManyToMany
Genre.java が主で ManyToMany となってます。同じ双方向 ManyToMany でも主側が genre テーブルになってます。
GENRE_NAME_1 が NOT NULL になっているからでしょう。
次に同じくジョインテーブルを利用したリレーションシップをとっている email テーブルから生成されたエンティティクラスを確認します。
Talent.java
Email.java
Talent.java が従で ManyToMany
Email.java が主で ManyToMany
さきほどの Genre.java と一緒ですね。
本当は単方向 OneToMany を実現するためにジョインテーブルを用意したのだけどNetBeans6.0 はそこまで解るはずがないのでこのようになりました。
つまりジョインテーブルを利用すると双方向 ManyToMany になってしまうようです。
次はaddress テーブルから生成されたエンティティクラスを確認します。
Talent.java
Address.java
Talent.java が主で ManyToOne です。
Address.java が主で OneToManyです。
これは Office.java と一緒ですね。
本当は単方向 OneToOne にする予定だったのですがこのようになってしまいました。
あとで修正すれば問題なさそうです。
次は phone テーブルから生成されるエンティティクラスを確認します。
Talent.java
Phone.java
Talent.java が従で OneToOne です。
カスケード戦略がとられてます。
Phone.java が主で OneToOne です。
読み取り専用属性が指定されてます。
ちゃんとテーブル構造を解析してくれてますね。
素晴らしいです。
データベースのテーブル構造を解析しエンティティクラスを自動生成する機能は素晴らしいものです。
恐るべし! NetBeans6.0 !