ドメインで文字列のキーをIDにする その2
ドメインで文字列のキーをIDにする
http://d.hatena.ne.jp/kkz_tech/20130606/1370609690
上の続きで、レガシーDBを使ってGrailsのドメインクラスを作る場合のお話です。
※前提条件としては、テーブル定義は変更できないもの、としています。
いくらレガシーといえど、テーブルの親子関係くらいはありますよね。
前回の例だとユーザーを作りましたから、今度はさらにユーザーを親とする子テーブル、ユーザーのログイン履歴に相当するものを作ってみました。
何個か引っかかるポイントはあったのですが、まずは親のインスタンスをどう持たせるか、です。適当に指定したら親テーブルとの外部キーであるユーザーIDが2個出来てしまう(;´∀`)
ログイン履歴はタイムスタンプ型のログイン日付とユーザーIDの複合主キーなわけですが、これはstatic mappingに以下のような指定をする事で思った通りのレコードになりました。
class LoginHistory { LoginUser loginUser Date loginDate static mapping = { id generator: 'assigned', composite: ['loginUser', 'loginDate'] loginUser column: 'user_id' }
ただ、このままではrun-app時にエラーが出てしまう。どうやら、ドメインクラスを比較する際にComparatorを使っているようなのですが、id列を持たせないようにしてしまった場合、そのためのメソッドが無いとダメみたいです。hashCode()とequals()を実装してあげると以下のような感じです。
コメントで教えて頂いたのですが、ドメインクラス自体にアノテーションで@EqualsAndHashCodeを指定するやり方もある模様。今度試したらまたエントリ作りますね。
hashCode、equalsともに「何を持って一意とするか(=主キー相当のプロパティは何か)」をきちんと意識する必要があります。って当たり前か。
class LoginHistory implements Serializable { boolean equals(other) { if (!(other instanceof LoginHistory)) { return false } return (other.loginUser.userId == loginUser.userId && other.loginDate == loginDate) } int hashCode() { def builder = new HashCodeBuilder() builder.append loginUser.userId builder.append loginDate builder.toHashCode() } }
とりあえず上記を踏まえて出来上がったのは、以下のような感じです。
レコードの作成日、更新日のカラムは既に持っていましたが、名前がGORMのデフォルトと違うので、自分で指定しています。
import java.util.Date; import org.apache.commons.lang.builder.HashCodeBuilder; class LoginHistory implements Serializable { LoginUser loginUser Date loginDate Date dateCreated Date lastUpdated String toString() { return loginUser.userId + toString(loginDate) } boolean equals(other) { if (!(other instanceof LoginHistory)) { return false } return (other.loginUser.userId == loginUser.userId && other.loginDate == loginDate) } int hashCode() { def builder = new HashCodeBuilder() builder.append loginUser.userId builder.append loginDate builder.toHashCode() } static constraints = { loginDate blank:false, nullable:false ip blank:true, nullable:true, maxSize:19 } static mapping = { table 'login_history' version false id generator: 'assigned', composite: ['loginUser', 'loginDate'] loginUser column: 'user_id' dateCreated column: 'insert_date' lastUpdated column: 'update_date' } }
実際のテーブルがどう出来ているかと言うとログイン履歴はこんな感じ。
\d login_history テーブル "public.login_history" カラム | 型 | 修飾語
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
親テーブルのユーザーマスタはこんな感じ。
# \d login_user テーブル "public.login_user" カラム | 型 | 修飾語
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-