LittleSoft J-Programming
4.1. 型付けされたテーブルオブジェクト
この章では、WebSQLTable の新機能について説明します。
LSJ の新機能では、テーブルオブジェクトの構造を、ジェネリックス による型指定で定義できるようになりました。
これにより、データ型について安全なコードが よりシンプルなコーディングで実装可能になります。
また、項目指定にデータベース物理カラム名が不要となるため、DB 依存性も低下します。
データ構造を定義したクラス(エンティティクラス)をテーブルクラスに指定することで、特定のエンティティ型に対応付けされた
テーブルオブジェクトを利用できるようになります。
LSJ の新機能では、テーブルオブジェクトの構造を、ジェネリックス による型指定で定義できるようになりました。
これにより、データ型について安全なコードが よりシンプルなコーディングで実装可能になります。
また、項目指定にデータベース物理カラム名が不要となるため、DB 依存性も低下します。
データ構造を定義したクラス(エンティティクラス)をテーブルクラスに指定することで、特定のエンティティ型に対応付けされた
テーブルオブジェクトを利用できるようになります。
エンティティクラスによる型付け
Employeeクラスのテーブルオブジェクトを作成する
/* Employeeクラスのテーブルオブジェクトを作成する */
public Table<Employee> tableEmp = new Table<Employee>();
public 宣言することにより、テンプレートからのアクセスが可能になります。
public Table<Employee> tableEmp = new Table<Employee>();
データ項目の参照
/* データ項目の参照 */
Employee emp = tableEmp.entity;
System.out.println("社員ID:" + emp.id );
System.out.println("社員名:" + emp.name );
tableEmp.entity でカーソル行のエンティティオブジェクトへのショートカットを表します。Employee emp = tableEmp.entity;
System.out.println("社員ID:" + emp.id );
System.out.println("社員名:" + emp.name );
tableEmp.getEntity(); で取得できるオブジェクトと同じ内容です。
また、Row クラスを Employee クラスで型付けすることも可能です。
データ項目の設定
/* データ項目の設定 */
Employee emp = tableEmp.startEditing();
emp.id = 1234;
emp.name = "熊谷 曜子";
tableEmp.validate(emp);
※従来のメソッドも全て利用可能です。
Employee emp = tableEmp.startEditing();
emp.id = 1234;
emp.name = "熊谷 曜子";
tableEmp.validate(emp);
エンティティクラスの作成
引数なしコンストラクタを持つ Java クラスをエンティティクラスとして指定することができます。
エンティティクラスの中で、以下のフィールドまたはメソッドがテーブルオブジェクトのカラムとして扱われます。
1. 可視性が public のデータフィールド
※ int, long等のプリミティブ型は使用不可、Integer, Long等のラッパークラスを使用する )
2. 可視性が public の getter, setter メソッド
※ getter のみ定義している場合は、読取専用の項目として扱われます。
getter なし(setter のみを定義)はカラムとして扱われません。
getter, setter メソッドは以下のような計算式でも構いません。
エンティティクラスの中で、以下のフィールドまたはメソッドがテーブルオブジェクトのカラムとして扱われます。
1. 可視性が public のデータフィールド
※ int, long等のプリミティブ型は使用不可、Integer, Long等のラッパークラスを使用する )
2. 可視性が public の getter, setter メソッド
※ getter のみ定義している場合は、読取専用の項目として扱われます。
getter なし(setter のみを定義)はカラムとして扱われません。
getter, setter メソッドは以下のような計算式でも構いません。
/* Workクラスを定義 */
public static class Work {
public Integer finishTimeM = new Integer(0);
public Integer beginTimeM = new Integer(0);
public Integer breakTimeM = new Integer(0);
// workTimeM を計算式で定義します
public Integer getWorkTimeM() { return finishTimeM - beginTimeM - breakTimeM; }
}
public static class Work {
public Integer finishTimeM = new Integer(0);
public Integer beginTimeM = new Integer(0);
public Integer breakTimeM = new Integer(0);
// workTimeM を計算式で定義します
public Integer getWorkTimeM() { return finishTimeM - beginTimeM - breakTimeM; }
}
データベーステーブルとのマッピング
エンティティクラス とデータベーステーブルは、以下のルールで対応付け(マッピング)が自動的に行われます。
1. エンティティクラス名、フィールド名、メソッド名("set","get" )から、
データベース内のテーブル名、カラム名を自動的に決定します。
※駱駝表記の java オブジェクト名をアンダースコア区切りの DB オブジェクト名に自動変換します。
2. java コードと DB のデータ型対応付けは jp.littlesoft.data.Column.classToColtypeMap で
定義されています。
以下エンティティクラスEmployeeはDBテーブル EMPLOYEEと対応付けられます。
名前の自動変換では、うまくマッピングできない場合、以下のように TableDef アノテーション、ColumnDef アノテーションで DB オブジェクト名を明示することができます。
1. エンティティクラス名、フィールド名、メソッド名("set","get" )から、
データベース内のテーブル名、カラム名を自動的に決定します。
※駱駝表記の java オブジェクト名をアンダースコア区切りの DB オブジェクト名に自動変換します。
2. java コードと DB のデータ型対応付けは jp.littlesoft.data.Column.classToColtypeMap で
定義されています。
以下エンティティクラスEmployeeはDBテーブル EMPLOYEEと対応付けられます。
public static class Employee {
public Long id; public Integer deptCode; public String name; public Date enterDate; public Short sex; public BigDecimal salary; } |
⇔ |
CREATE TABLE EMPLOYEE (
ID BIGINT NOT NULL, DEPT_CODE INTEGER NOT NULL, NAME VARCHAR(50) NOT NULL, ENTER_DATE DATE NOT NULL, SEX SMALLINT NOT NULL, SALARY NUMERIC(9 , 2) NOT NULL ); |
// Employee を T_EMPテーブルにマッピングします
@TableDef(name="T_EMP")
public static class Employee {
// id を EMP_ID にマッピングします
@ColumnDef(name="EMP_ID")
public Long id;
:
}
アノテーションでは、nameの他に caption, formatPattern, defaultValue, nullableなどが指定できます。@TableDef(name="T_EMP")
public static class Employee {
// id を EMP_ID にマッピングします
@ColumnDef(name="EMP_ID")
public Long id;
:
}
@TableDef(schema="PUBLIC", name="T_EMP")
public static class Employee {
@ColumnDef(name="EMP_ID", caption="社員ID")
public Long id;
@ColumnDef(caption="所属")
public Integer deptCode;
@ColumnDef(caption="氏名")
public String name;
@ColumnDef(caption="入社日", formatPattern="yyyy/MM/dd")
public Date enterDate;
@ColumnDef(caption="性別", defaultValue="1")
public Short sex;
@ColumnDef(caption="給与", formatPattern="#,##0.00;-#,##0.00")
public BigDecimal salary;
}
public static class Employee {
@ColumnDef(name="EMP_ID", caption="社員ID")
public Long id;
@ColumnDef(caption="所属")
public Integer deptCode;
@ColumnDef(caption="氏名")
public String name;
@ColumnDef(caption="入社日", formatPattern="yyyy/MM/dd")
public Date enterDate;
@ColumnDef(caption="性別", defaultValue="1")
public Short sex;
@ColumnDef(caption="給与", formatPattern="#,##0.00;-#,##0.00")
public BigDecimal salary;
}
エンティティクラスの生成ツール
jp.littlesoft.tools.SQLEntityClassWriter を利用するとデータベーススキーマをもとにエンティティクラスの java ソースを自動生成することができます。
SQLEntityClassWriter は Java アプリケーションです。 java コマンドラインで以下のような引数を設定して実行してください。
SQLEntityClassWriter は Java アプリケーションです。 java コマンドラインで以下のような引数を設定して実行してください。
jp.littlesoft.tools.SQLEntityClassWriter d=org.h2.Driver u=jdbc:h2:C:/mydb i=sa s=PUBLIC
引数
d | : JDBCドライバー名 |
u | : JDBC 接続 URL |
i | : USER 名 |
p | : パスワード |
s | : 対象スキーマ名 |
f | : 出力ファイル名 |
出力サンプル
public class DB implements Serializable {
@TableDef(name="DEPARTMENT")
public static class Department implements Serializable {
@ColumnDef(name="CODE")
public Integer code;
@ColumnDef(name="NAME")
public String name;
@ColumnDef(name="PARENT_CODE")
public Integer parentCode;
}
@TableDef(name="EMPLOYEE")
public static class Employee implements Serializable {
@ColumnDef(name="EMP_ID")
public Long empId;
@ColumnDef(name="DEPT_CODE")
public Integer deptCode;
@ColumnDef(name="NAME")
public String name;
@ColumnDef(name="ENTER_DATE")
public Date enterDate;
@ColumnDef(name="SEX")
public Short sex;
@ColumnDef(name="SALARY")
public BigDecimal salary;
@ColumnDef(name="MEMO")
public String memo;
@ColumnDef(name="CREATE_DATETIME")
public Timestamp createDatetime;
@ColumnDef(name="UPDATE_DATETIME")
public Timestamp updateDatetime;
}
@TableDef(name="DEPARTMENT")
public static class Department implements Serializable {
@ColumnDef(name="CODE")
public Integer code;
@ColumnDef(name="NAME")
public String name;
@ColumnDef(name="PARENT_CODE")
public Integer parentCode;
}
@TableDef(name="EMPLOYEE")
public static class Employee implements Serializable {
@ColumnDef(name="EMP_ID")
public Long empId;
@ColumnDef(name="DEPT_CODE")
public Integer deptCode;
@ColumnDef(name="NAME")
public String name;
@ColumnDef(name="ENTER_DATE")
public Date enterDate;
@ColumnDef(name="SEX")
public Short sex;
@ColumnDef(name="SALARY")
public BigDecimal salary;
@ColumnDef(name="MEMO")
public String memo;
@ColumnDef(name="CREATE_DATETIME")
public Timestamp createDatetime;
@ColumnDef(name="UPDATE_DATETIME")
public Timestamp updateDatetime;
}
エンティティクラスからデータベーススキーマを生成する
jp.littlesoft.sql.SchemaUpdator クラスを利用すると、DDLを作成せずに、直接エンティティクラス情報からデータベースのスキーマを生成することが出来ます。
下記のコード例では、addPrimary メソッドで主キーの定義を追加しています。
引数は作成対象のエンティティクラスです。
データベーススキーマとの差分を検出し、変更DDLを自動的に適用します。
1.エンティティクラスにITableDefインターフェースを実装し、メタ情報を定義する。
createMetaData メソッドをオーバーライドすると、メタ情報を生成するコードを実装するようになります。下記のコード例では、addPrimary メソッドで主キーの定義を追加しています。
public class DB {
public static class UserGroup implements ITableDef {
@ColumnDef(caption="グループID", nullable=Nullable.FALSE )
public Integer id;
@ColumnDef(caption="グループ名", length=80, nullable=Nullable.FALSE)
public String name;
// createMetaDataメソッドをオーバーライドし、このエンティティのメタ情報を生成するコードを実装します
@Override
public MetaData<?> createMetaData() {
return new MetaData<UserGroup>() {{
// ここでは主キーの定義を行っています
addPrimaryKey($$.id);
}};
}
}
createMetaData メソッドでは、主キーの定義の他にも外部キー、インデックスの定義などが行えます。
public static class UserGroup implements ITableDef {
@ColumnDef(caption="グループID", nullable=Nullable.FALSE )
public Integer id;
@ColumnDef(caption="グループ名", length=80, nullable=Nullable.FALSE)
public String name;
// createMetaDataメソッドをオーバーライドし、このエンティティのメタ情報を生成するコードを実装します
@Override
public MetaData<?> createMetaData() {
return new MetaData<UserGroup>() {{
// ここでは主キーの定義を行っています
addPrimaryKey($$.id);
}};
}
}
public static class User implements ITableDef {
@ColumnDef(caption="ユーザーID", length=32, nullable=Nullable.FALSE )
public String id;
@ColumnDef(caption="ユーザー名", length=80, nullable=Nullable.FALSE)
public String name;
@ColumnDef(caption="グループID", nullable=Nullable.TRUE )
public Integer groupId;
// createMetaDataメソッドをオーバーライドし、このエンティティのメタ情報を生成するコードを実装します
@Override
public MetaData<?> createMetaData() {
return new MetaData<USer>() {{
addPrimaryKey($$.id);
// 外部キーの定義を行います
addForeginKey($$.groupId)
// 参照先テーブルのエンティティクラスを指定します
.references(Group.class)
// onDelete、onUpdateのオプション設定も可能
.onDelete(FKOption.RESTRICT)
.onUpdate(FKOption.SET_NULL)
// 外部キーにインデックスを指定する場合はtrueを指定します
.usingIndex(true);
// NAMEに対する単独インデックスを定義します。
addIndex($$.name);
}};
}
}
@ColumnDef(caption="ユーザーID", length=32, nullable=Nullable.FALSE )
public String id;
@ColumnDef(caption="ユーザー名", length=80, nullable=Nullable.FALSE)
public String name;
@ColumnDef(caption="グループID", nullable=Nullable.TRUE )
public Integer groupId;
// createMetaDataメソッドをオーバーライドし、このエンティティのメタ情報を生成するコードを実装します
@Override
public MetaData<?> createMetaData() {
return new MetaData<USer>() {{
addPrimaryKey($$.id);
// 外部キーの定義を行います
addForeginKey($$.groupId)
// 参照先テーブルのエンティティクラスを指定します
.references(Group.class)
// onDelete、onUpdateのオプション設定も可能
.onDelete(FKOption.RESTRICT)
.onUpdate(FKOption.SET_NULL)
// 外部キーにインデックスを指定する場合はtrueを指定します
.usingIndex(true);
// NAMEに対する単独インデックスを定義します。
addIndex($$.name);
}};
}
}
2.SchemaUpdatorクラスを使用して、データベーススキーマを生成する。
以下のように createOrAlterTable メソッドを使用すると、スキーマを作成します。引数は作成対象のエンティティクラスです。
Class.forName("org.h2.Driver");
Connection conn = DriverManager.getConnection("jdbc:h2:C:/sample/lsjsample", "sa", "");
new SchemaUpdator(conn).createOrAlterTable(
// 作成対象のエンティティクラス列挙します
DB.UserGroup.class,
DB.User.class
);
これにより以下のDDLが生成されデータベースに適用されます。
Connection conn = DriverManager.getConnection("jdbc:h2:C:/sample/lsjsample", "sa", "");
new SchemaUpdator(conn).createOrAlterTable(
// 作成対象のエンティティクラス列挙します
DB.UserGroup.class,
DB.User.class
);
CREATE TABLE USER_GROUP (
ID INTEGER NOT NULL
,NAME VARCHAR(80) NOT NULL
);
ALTER TABLE USER_GROUP ADD CONSTRAINT USER_GROUP_PK PRIMARY KEY (ID);
CREATE TABLE USER (
ID VARCHAR(32) NOT NULL
,NAME VARCHAR(80) NOT NULL
,GROUP_ID INTEGER NULL
);
ALTER TABLE USER ADD CONSTRAINT USER_PK PRIMARY KEY (ID);
CREATE INDEX USER_IX4cd4defb ON USER(GROUP_ID);
CREATE INDEX USER_IX24728b ON USER(NAME);
ALTER TABLE USER ADD CONSTRAINT USER_FKb69ca66f
FOREIGN KEY (GROUP_ID) REFERENCES USER_GROUP (ID) ON UPDATE SET NULL;
ID INTEGER NOT NULL
,NAME VARCHAR(80) NOT NULL
);
ALTER TABLE USER_GROUP ADD CONSTRAINT USER_GROUP_PK PRIMARY KEY (ID);
CREATE TABLE USER (
ID VARCHAR(32) NOT NULL
,NAME VARCHAR(80) NOT NULL
,GROUP_ID INTEGER NULL
);
ALTER TABLE USER ADD CONSTRAINT USER_PK PRIMARY KEY (ID);
CREATE INDEX USER_IX4cd4defb ON USER(GROUP_ID);
CREATE INDEX USER_IX24728b ON USER(NAME);
ALTER TABLE USER ADD CONSTRAINT USER_FKb69ca66f
FOREIGN KEY (GROUP_ID) REFERENCES USER_GROUP (ID) ON UPDATE SET NULL;
3.スキーマの修正、変更を行う。
エンティティクラスの修正・変更を行った後、createOrAlterTable メソッドを実行するとデータベーススキーマとの差分を検出し、変更DDLを自動的に適用します。
// 桁の変更(length=80 → 120)
@ColumnDef(caption="グループ名", length=120, nullable=Nullable.FALSE)
public String name;
// データ型の変更(String → Long)
@ColumnDef(caption="ユーザーID", nullable=Nullable.FALSE )
public Long id;
// カラム名の変更(GROUP_ID → GID)
@ColumnDef(oldName="GROUP_ID" caption="グループID", nullable=Nullable.TRUE )
public Integer gid;
// アノテーション(oldName)で変更前の物理カラム名を指定します
// createOrAlterTableメソッドを再実行
new SchemaUpdator(conn).createOrAlterTable(
UserGroup.class,
User.class,
);
実行すると、以下のようなALTER文が生成・適用されます。
@ColumnDef(caption="グループ名", length=120, nullable=Nullable.FALSE)
public String name;
// データ型の変更(String → Long)
@ColumnDef(caption="ユーザーID", nullable=Nullable.FALSE )
public Long id;
// カラム名の変更(GROUP_ID → GID)
@ColumnDef(oldName="GROUP_ID" caption="グループID", nullable=Nullable.TRUE )
public Integer gid;
// アノテーション(oldName)で変更前の物理カラム名を指定します
// createOrAlterTableメソッドを再実行
new SchemaUpdator(conn).createOrAlterTable(
UserGroup.class,
User.class,
);
// グループ名 の桁変更
ALTER TABLE USER_GROUP ALTER COLUMN NAME VARCHAR(120) NOT NULL;
// ユーザID の型変更
ALTER TABLE USER ALTER COLUMN ID BIGINT NOT NULL;
// グループID の物理カラム名変更
ALTER TABLE USER ALTER COLUMN GROUP_ID RENAME TO GID;
※ 上記の変更以外にも、DECIMAL 型の Presision、Scale、NULL制約、デフォルト値の変更に対応します。
ALTER TABLE USER_GROUP ALTER COLUMN NAME VARCHAR(120) NOT NULL;
// ユーザID の型変更
ALTER TABLE USER ALTER COLUMN ID BIGINT NOT NULL;
// グループID の物理カラム名変更
ALTER TABLE USER ALTER COLUMN GROUP_ID RENAME TO GID;