- PR -

世代管理されるテーブルのO/Rマッパ適用について

1
投稿者投稿内容
TAKA
会議室デビュー日: 2007/06/03
投稿数: 19
投稿日時: 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マッパーの利点を活かせるのでしょうか?

・逆にテーブル定義を修正すべきであれば、どのようにするべきでしょうか?

よろしくお願いいたします。

だっちょ
大ベテラン
会議室デビュー日: 2006/12/05
投稿数: 115
投稿日時: 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();

で検索できると思います。
TAKA
会議室デビュー日: 2007/06/03
投稿数: 19
投稿日時: 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設計観点に関わらず、アドバイス頂戴できれば有難いです。
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2008-11-14 14:54
引用:

TAKAさんの書き込み (2008-11-14 12:15) より:
マスタに有効開始日・終了日を持たせたせいで、単純なone-to-manyでの(1)が
ほとんど利用出来なくなり、(2),(3)中心の実装になってしまうのでは、
O/Rマッパーを活かしきれていないのでは・・と悩んでおります。


単にシステム日付で使うべきレコードを判断できるのであれば、
ビューに対してマッピングしたエンティティを用意する手もあります。

ただ、実際にはマスタのバージョン管理を行おうとすると、
システム日付だけでは不十分で、利用する側のレコードの日付によって
扱うマスタのレコードを切り替えなければならない場面も出てくるので、
そういったところではクエリで何とかしないといけなくなります。

この辺はO/Rマッパーを使っても使わなくても、どのみち扱いにくいです。
TAKA
会議室デビュー日: 2007/06/03
投稿数: 19
投稿日時: 2008-11-14 16:01
あしゅ様、ありがとうございます。
引用:

ただ、実際にはマスタのバージョン管理を行おうとすると、
システム日付だけでは不十分で、利用する側のレコードの日付によって
扱うマスタのレコードを切り替えなければならない場面も出てくるので、
そういったところではクエリで何とかしないといけなくなります。

この辺はO/Rマッパーを使っても使わなくても、どのみち扱いにくいです。



まさに上記が悩みの種で、たとえば
■販売履歴テーブル
 販売日, 商品コード
 1/1 , AAA
 2/1 , AAA

上記のような、商品コードを外部キーに持つ、テーブルと商品マスタをJOINするときに、
「商品マスタ.有効開始日 ≦ 販売履歴.販売日 ≦ 商品マスタ.有効開始日」
という条件を毎回指定しなくてはなりません。

(乱暴なイメージですが)上記の条件自体を、商品マスタと販売履歴の
『関連』として、マッピング設定ファイルなどで固定的に指定できないものかと、
調べておりました。
↑のような事は不可能でしょうか?

また、いっそのこと正規化せずに、販売履歴にその時点のマスタ情報も
持たせようか、などとも検討しております。
↑は邪道でしょうか?
だっちょ
大ベテラン
会議室デビュー日: 2006/12/05
投稿数: 115
投稿日時: 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 商品コード;
}


かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2008-11-14 17:00
開始日と終了日をエンティティの属性ではなく、
キーとして利用しているのが問題でしょうね。

物理的な商品は同じでも、販売時期によって価格が違うのであれば、
商品名も商品コードも同じ、全く別の商品として扱う方がシンプルかと思います。

商品テーブル
商品ID 商品コード 開始日 終了日・・・

販売テーブル
商品ID・・・

これなら販売履歴を探す場合、1:Nの関係になります。
TAKA
会議室デビュー日: 2007/06/03
投稿数: 19
投稿日時: 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

スキルアップ/キャリアアップ(JOB@IT)