- - PR -
世代管理されるテーブルのO/Rマッパ適用について
1
投稿者 | 投稿内容 | ||||
---|---|---|---|---|---|
|
投稿日時: 2008-11-14 10:13
お世話になります。
以下のような、データを世代管理するテーブル設計の場合、 HibernateなどのO/Rマッパーを有効利用できるのでしょうか? ■商品マスタ 有効開始日,有効終了日,商品コード,価格 1/1 , 1/31 , AAA , 1000 2/1 , 2,15 , AAA , 2000 2/16 , 12/31 , AAA , 3000 ※同一商品コードで、有効期間の重複は無し。 上記テーブル定義にした理由は、期間限定の価格変更などを、 事前登録(予約)可能としたいためです。 この場合、販売履歴などのデータテーブルとN:N(many-to-many)の関連になってしまい、 ある時点で有効な商品コード=AAAを抽出する場合は、 常に有効開始日・終了日の範囲指定を行う必要があるため、 大半がSQL指定での実装になってしまうのではと、懸念しています。 ■質問 ・上記のテーブル定義の場合でも、マッピング設定等を工夫する事で O/Rマッパーの利点を活かせるのでしょうか? ・逆にテーブル定義を修正すべきであれば、どのようにするべきでしょうか? よろしくお願いいたします。 | ||||
|
投稿日時: 2008-11-14 11:22
Hilbertは少し違うのかもしれませんが、JPQLで検索する場合、有効開始日と有効終了日をTimestampで入れておけば
entityManager.createQuery("SELECT e FROM 商品マスタ e WHERE e.商品コード='AAA' AND e.有効開始日 <= :now AND e.有効終了日 >= :now").setParameter("now", new Timestamp(date.getTime())).getResultList(); で検索できると思います。 | ||||
|
投稿日時: 2008-11-14 12:15
だっちょ様、ありがとうございます。
Hibernate,JPAを採用した場合の、単純なコーディング量を考えた場合、 (1)findのようなAPIのメソッドで実装。 (2)HQL,JPQLを利用した実装。 (3)SQLを利用した実装。 の順になるかと思います。 マスタに有効開始日・終了日を持たせたせいで、単純なone-to-manyでの(1)が ほとんど利用出来なくなり、(2),(3)中心の実装になってしまうのでは、 O/Rマッパーを活かしきれていないのでは・・と悩んでおります。 マッピング設定やテーブル定義を工夫して、(1)の利用が出来るように ならないかと検討しているのですが、困難でしょうか? Hibernate、JPA、DB設計観点に関わらず、アドバイス頂戴できれば有難いです。 | ||||
|
投稿日時: 2008-11-14 14:54
単にシステム日付で使うべきレコードを判断できるのであれば、 ビューに対してマッピングしたエンティティを用意する手もあります。 ただ、実際にはマスタのバージョン管理を行おうとすると、 システム日付だけでは不十分で、利用する側のレコードの日付によって 扱うマスタのレコードを切り替えなければならない場面も出てくるので、 そういったところではクエリで何とかしないといけなくなります。 この辺はO/Rマッパーを使っても使わなくても、どのみち扱いにくいです。 | ||||
|
投稿日時: 2008-11-14 16:01
あしゅ様、ありがとうございます。
まさに上記が悩みの種で、たとえば ■販売履歴テーブル 販売日, 商品コード 1/1 , AAA 2/1 , AAA 上記のような、商品コードを外部キーに持つ、テーブルと商品マスタをJOINするときに、 「商品マスタ.有効開始日 ≦ 販売履歴.販売日 ≦ 商品マスタ.有効開始日」 という条件を毎回指定しなくてはなりません。 (乱暴なイメージですが)上記の条件自体を、商品マスタと販売履歴の 『関連』として、マッピング設定ファイルなどで固定的に指定できないものかと、 調べておりました。 ↑のような事は不可能でしょうか? また、いっそのこと正規化せずに、販売履歴にその時点のマスタ情報も 持たせようか、などとも検討しております。 ↑は邪道でしょうか? | ||||
|
投稿日時: 2008-11-14 16:53
問題がよく分かってませんが、履歴とマスタを関連させたいだけなら、単にリレーションを設定しただけでよいのでは?
@Entity @Table public class 履歴 { @Id public Long id; @ManyToOne public 商品マスタ master; @Column public Timestamp 販売日; } @Entity @Table public class 商品マスタ { @OneToMany(mappedBy="id", fetch=FetchType.LAZY) public Collection<履歴> history; @Column public Timestamp 販売開始日; @Column public Timestamp 販売終了日; @Column public String 商品コード; } | ||||
|
投稿日時: 2008-11-14 17:00
開始日と終了日をエンティティの属性ではなく、
キーとして利用しているのが問題でしょうね。 物理的な商品は同じでも、販売時期によって価格が違うのであれば、 商品名も商品コードも同じ、全く別の商品として扱う方がシンプルかと思います。 商品テーブル 商品ID 商品コード 開始日 終了日・・・ 販売テーブル 商品ID・・・ これなら販売履歴を探す場合、1:Nの関係になります。 | ||||
|
投稿日時: 2008-11-14 18:52
TO:かつのり様
ありがとうございます。なるほど!! 言われてみれば、という感じですが、私の発想が貧弱でした。 TO:だっちょ様 説明下手で申し訳ありませんでした。 通常1:Nの、マスタ・トランの関連であれば、 ---------------------------------------- TranEntity tran = manager.find(トラン.KEY); int price = tran.getMaster().getPrice(); ---------------------------------------- のイメージで実装できるところを、 マスタのキーに有効範囲を持たせた事で、 ---------------------------------------- P層Model model = manager.createQuery("select ・・・ from master,tran ・・・ where master.開始日 ≦ tran.販売日 ≦ master.終了日") ---------------------------------------- のような実装が毎回必要になってしまうと思い込んでおり、 APまたはDBの工夫によって、上記を改善出来ないか?に苦慮していた次第です。 かつのり様の方法で、検討を進めたいと思います。 ありがとうございました。 |
1