LoginSignup
1
0

More than 5 years have passed since last update.

2017年度 Java 永続化フレームワークについての考察(8) Hibernate5

Posted at

前ポスト

前置き

隙間時間を利用して書いているので精度の甘い箇所があれば、ご指摘いただけると幸いです。
まず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

テーブル構成

employeeテーブルからpostテーブルにID紐づけ

対応範囲

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とかの読込が必要

後ポスト

まだない。

参考記事

1
0
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0