#前ポスト
- 2017年度 Java 永続化フレームワークについての考察(1)
- 2017年度 Java 永続化フレームワークについての考察(2) Doma2
- 2017年度 Java 永続化フレームワークについての推測(3) Reladomo
- 2017年度 Java 永続化フレームワークについての考察(4) jOOQ
- 2017年度 Java 永続化フレームワークについての考察(5) Iciql
- 2017年度 Java 永続化フレームワークについての考察(6) Ebean
- 2017年度 Java 永続化フレームワークについての考察(7) EclipseLink
#前置き
隙間時間を利用して書いているので精度の甘い箇所があれば、ご指摘いただけると幸いです。
まずEOLであるものは除外。
有償の機能については検討対象に含むが、実際に使用はしません、懐の問題で。
「まぁ、たぶん明記されてなくてもPostgreならいけるだろ」ぐらいの間抜けな理由で使用DBはPostgreに固定。
#環境
- PostgreSQL 9.6.3
-
5.2 series - Hibernate ORM
- hibernate-core:5.2.12.Final
- hibernate-entitymanager:5.2.12.Final
- hibernate-java8:5.2.12.Final
- hibernate-jpamodelgen:5.2.12.Final
- Java 64bit 8u144
#対応範囲
ORM | Transaction | Data Model | DSL |
---|---|---|---|
○ | ○ | ※ | ○ |
○:対応 | |||
×:非対応 | |||
※:多対多の関係性である場合、関連テーブルの作成を行う機能がある |
#所感
- エンティティの自動生成がないのツラい
- 設定ファイルが重い、実に重い
- 旧版まではあったマッピングファイルのclass直下one-to-many要素がないので迷った
- bagとかsetとかのコレクション系要素の子要素に移っている、まぁ、確かにその通りだ
#サンプル
##単テーブル検索
###全件検索
Main.java
// JPQLを最初に推してくるチュートリアル……しかも型安全じゃないの……
session.createQuery("from Employee").list().stream().forEach(o -> {
Employee e = (Employee)o;
Main.sysout(e);
});
// CriteriaBuilderでも良いのに、チュートリアルなんなの……
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Employee> query = builder.createQuery(Employee.class);
Root<Employee> root = query.from(Employee.class);
session.createQuery(query.select(root).select(root)).getResultList().stream().forEach(Main::sysout);
// EntityManagerからでもJPQLを推してくるチュートリアル……
em.createQuery("from Employee", Employee.class).getResultList().stream().forEach(Main::sysout);
// やっぱりCriteriaBuilderで良い、チュートリアルなんなの……
CriteriaBuilder builder2 = em.getCriteriaBuilder();
CriteriaQuery<Employee> query2 = builder2.createQuery(Employee.class);
Root<Employee> root2 = query2.from(Employee.class);
em.createQuery(query2.select(root2).select(root2)).getResultList().stream().forEach(Main::sysout);
Main#sysout(Employee).java
public static void sysout(Employee e) {
System.out.format("%1s: %2s, %3s, %4s\n", e.id, e.first_name, e.middle_name, e.last_name);
}
###主キー検索
Main.java
// session使う版
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Employee> query = builder.createQuery(Employee.class);
Root<Employee> root = query.from(Employee.class);
session.createQuery(query.select(root).select(root).where(builder.equal(root.get(Employee_.id), 1L)))
.getResultList()
.stream()
.forEach(Main::sysout);
// EntityManager使う版
CriteriaBuilder builder2 = em.getCriteriaBuilder();
CriteriaQuery<Employee> query2 = builder2.createQuery(Employee.class);
Root<Employee> root2 = query2.from(Employee.class);
em.createQuery(query2.select(root2).select(root2).where(builder2.equal(root2.get(Employee_.id), 1L)))
.getResultList()
.stream()
.forEach(Main::sysout);
##テーブル結合
Main.java
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Employee> query = builder.createQuery(Employee.class);
Root<Employee> root = query.from(Employee.class);
session.createQuery(query.select(root).select(root).where(builder.equal(root.get(Employee_.id), 1L)))
.getResultList()
.stream()
.peek(Main::sysout)
.map(e -> e.posts)
.flatMap(ps -> ps.stream())
.forEach(Main::sysout);
CriteriaBuilder builder2 = em.getCriteriaBuilder();
CriteriaQuery<Employee> query2 = builder2.createQuery(Employee.class);
Root<Employee> root2 = query2.from(Employee.class);
em.createQuery(query2.select(root2).select(root2).where(builder2.equal(root2.get(Employee_.id), 0L)))
.getResultList()
.stream()
.peek(Main::sysout)
.map(e -> e.posts)
.flatMap(ps -> ps.stream())
.forEach(Main::sysout);
Main#sysout(Post).java
public static void sysout(Post p) {
System.out.format("\t%1s: %2s, %3s\n", p.id, p.employee_id, p.name);
}
Employee.java
@Entity
@Table(name="employee")
public class Employee {
@Id
public long id;
public String first_name;
public String middle_name;
public String last_name;
@OneToMany(fetch = FetchType.EAGER)
@JoinColumn(name = "id", referencedColumnName = "employee_id", table = "post")
public List<Post> posts = new ArrayList<>();
public long getId() {return this.id;}
public void setId(long id) {this.id = id;}
public String getFirst_name() {return this.first_name;}
public void setFirst_name(String first_name) {this.first_name = first_name;}
public String getMiddle_name() {return this.middle_name;}
public void setMiddle_name(String middle_name) {this.middle_name = middle_name;}
public String getLast_name() {return this.last_name;}
public void setLast_name(String last_name) {this.last_name = last_name;}
public List<Post> getPosts() {return this.posts;}
public void setPosts(List<Post> posts) {this.posts = posts;}
}
Post.java
@Entity
@Table(name = "post")
public class Post {
@Id
public long id;
public long employee_id;
public String name;
public long getId() {return this.id;}
public void setId(long id) {this.id = id;}
public long getEmployee_id() {return this.employee_id;}
public void setEmployee_id(long employee_id) {this.employee_id = employee_id;}
public String getName() {return this.name;}
public void setName(String name) {this.name = name;}
}
Employee.hbm.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="hibernate.models">
<class name="Employee" table="employee">
<id name="id" column="id"/>
<property name="first_name" column="first_name"/>
<property name="middle_name" column="middle_name"/>
<property name="last_name" column="last_name"/>
<bag name="posts" table="post">
<key column="employee_id"/>
<one-to-many class="Post"/>
</bag>
</class>
</hibernate-mapping>
Post.hbm.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="hibernate.models">
<class name="Post" table="post">
<id name="id" column="id"/>
<property name="employee_id" column="employee_id"/>
<property name="name" column="name"/>
</class>
</hibernate-mapping>
#要点
- ほぼJPA実装
- 設定がヘビーなので専門家がいないと安心して運用はできない気がする
- マッピングXMLに合わせてDDLを発行したりできる、無論選択できるけど楽なような怖いような……
#ハマったポイント
- 「JPA実装だしEclipseLinkと同じでいけるよね」
- 動かない
- そもそもマッピングXMLとか書いてなかった
- 動かない
- 「JPAのアノテーションと同じ感じでいけるよね」
- 前述の通り、one-to-manyがプロパティと同レベルじゃない、まずはDTDとかの読込が必要
#後ポスト
まだない。
#参考記事