ラベル JPA の投稿を表示しています。 すべての投稿を表示
ラベル JPA の投稿を表示しています。 すべての投稿を表示

2013年11月21日木曜日

JPAとHibernateのCascadeTypeにハマりました。。。


Hibernateでエンティティの関連性にCascadeTypeを使うと、データ取得だけとか、更新もするとか、いろいろ指定できるはずなのですが、できない??結構ハマったのですが、いろいろと調べると参考になるサイトに、JPAとHibernateでそれぞれCascadeTypeのアノテーションがあり、HibernateのSessionを使っているとJPAのCascadeTypeでは予測した挙動で動いてくれないようです。これはハマる!!

org.hibernate.annotations.CascadeType
javax.persistence.CascadeType
は違う!!

JPA
 @OneToMany(fetch = FetchType.LAZY, 
       cascade = {CascadeType.PERSIST,CascadeType.MERGE }, 
       mappedBy = "stock")
Hibernate
@OneToMany(fetch = FetchType.LAZY, mappedBy = "stock")
@Cascade({CascadeType.SAVE_UPDATE})

それにしても、@OneToManyはjavax.persistenceで、@Cascadeはorg.hibernate.annotations、ややこしい。。。

http://docs.jboss.org/hibernate/core/3.5/javadocs/org/hibernate/annotations/CascadeType.html
http://docs.oracle.com/javaee/6/api/javax/persistence/CascadeType.html

2013年11月7日木曜日

とりあえずHibernateのエンティティマッピングの書き方をすぐ忘れてしまうので。。。

とりあえずHibernateのエンティティマッピングの書き方をすぐ忘れてしまうので、一番すっきりとしていて分かりやすいお手本のリンクをメモっておくことにした。

http://en.wikibooks.org/wiki/Java_Persistence/OneToOne

Hibernateでカラムのソートの昇順・降順を指定するには@OrderByを使う

@OrderColumnの落とし穴 でHibernateのエンティティで一対多の関係を持ったコレクションのフィールドで@OrderColumnを使用した場合に、java.util.Listがnullオブジェクトを追加してしまうのでjava.util.Setを使う事にしました。

じゃあそのコレクションのソート降順・昇順の指定はどうなるんだ?という事ですが、@OrderByで指定できるようです。中身は@OrderBy("ID ASC")もしくは@OrderBy("ID DESC")のように、ここはシンプルに指定できます。また、なぜか@OrderColumnは指定する必要が無い事に気づきました。なんで???

またもやHibernateの未知なブラックボックスです。どうやって@OrderByと@OrderColumnを使い分けるのだろう??

http://stackoverflow.com/questions/11433195/hibernate-orderby-vs-ordercolumn-to-maintain-the-order-of-a-collection

2013年11月6日水曜日

@OrderColumnの落とし穴

@OrderColumnにハマった。。。Stackoverflowで書いてある状況と全く同じで、一対多の関連性のあるエンティティで多の方のエンティティにListを使っていると、何故かデータベースのテーブルに無いレコードがNullとしてListに入っている。????ここにハマった。

要するにListと使って多エンティティを保持すると、保持される順序を指定しないといけないので@OrderColumnを使うのだが、ここの仕様がややこしくてブラックボックス。

The order column must be of integral type. The persistence provider maintains a contiguous (non-sparse) ordering of the values of the order column when updating the association or element collection. The order column value for the first element is 0.
※contiguous=切れ目の無い

と、JavaDocを読んでててイマイチ不明なのだが、要するに@OrderColumnで指定するカラムがintの主キーで、400が一番若いIDだとすると、0~399まではテーブルには存在しないのだが、わざわざご丁寧に0~399までをnullオブジェクトとしてListの保存するわけだ。これが、contiguous (non-sparse) ordering. なんとお節介な機能だ。。。

そして、これを回避するにはList型でなくSet型を使って使うとnullオブジェクトが保持されなくなったのだが、どうもここはまだまだ奥が深そう。。。こういうところがHibernateの分かりにくいところ。。。

http://stackoverflow.com/questions/13307849/hibernate-returns-list-with-null-values-onetomany-annotation-with-list-type
http://docs.oracle.com/javaee/6/api/javax/persistence/OrderColumn.html

HibernateのFetchTypeがLAZYとEAGERの違い


2つのエンティティ(テーブル)が一対多の関連性を持つ場合、どのタイミングで多のエンティティをロードしてあげるか、FetchTypeで2通りのやり方がある。

@OneToMany(fetch=FetchType.EAGER)
@OneToMany(fetch=FetchType.LAZY)

例えば、大学(Univeristy)というエンティティと学生(Student)というエンティティが一対多で関連付けられているとすると、Listのstudentsにデータをロードするタイミングとして、他のフィールド(id, name, address)と同じタイミングでロードするEAGERと、getStudents()などのオンディマンドでゲッターを呼ぶ場合にロードするLAZYのやり方がある。

public class University {
 private String id;
 private String name;
 private String address;
 private List<Student> students;

 // setters and getters
}

使い分けるポイントとしては、studentsにどれだけのデータがロードされるか、一度に全てロードする事が得策かどうかを考える必要がある。

http://stackoverflow.com/questions/2990799/difference-between-fetchtype-lazy-and-eager-in-java-persistence

2013年10月25日金曜日

単一テーブル継承(Single Table Inheritance)

Hibernateの@Entityを実装している時に、RDBの特定のカラム値を元にポリモーフしたサブクラスを割り当てたい。つまり、抽象クラスを@Entityにして、サブクラスを実装するにはどうしたら良いか調べた。

あっさりとJPA仕様にやり方が書いてあるのを見つけたところ、どうやらSingle Table Inheritance(単一テーブル継承)というやり方がある事が分かった。

そのやり方をWikiから抜粋:

Single Table Inheritance[edit]

Single table inheritance is the simplest and typically the best performing and best solution. In single table inheritance a single table is used to store all of the instances of the entire inheritance hierarchy. The table will have a column for every attribute of every class in the hierarchy. A discriminator column is used to determine which class the particular row belongs to, each class in the hierarchy defines its own unique discriminator value.

Example single table inheritance table in database[edit]

PROJECT (table)
IDPROJ_TYPENAMEBUDGET
1LAccounting50000
2SLegalnull

Example single table inheritance annotations[edit]

@Entity
@Inheritance
@DiscriminatorColumn(name="PROJ_TYPE")
@Table(name="PROJECT")
public abstract class Project {
  @Id
  private long id;
  ...
}
@Entity
@DiscriminatorValue("L")
public class LargeProject extends Project {
  private BigDecimal budget;
}
@Entity
@DiscriminatorValue("S")
public class SmallProject extends Project {
}


ポイントは@DiscripnatorColumnを抽象クラスで指定して、@DiscriminatorValueを実装クラスで教えてあげる。これはかなり便利。