テーブルの結合

今回はテーブル結合です。

【前提条件】

[環境]
[その他]
  • 前回*1のデータやソースを一部再利用

【概要】

JPA2.0で提供されているアノテーションを使用して、
テーブル結合した結果をエンティティに設定します。

【サンプルコード】

[テーブル]

ユーザ権限を保持する「user_authority」というテーブルを作成します。

CREATE TABLE user_authority
(
    seq_number serial NOT NULL,
    auth_user_id character varying(10) NOT NULL,
    authority_type integer,
    CONSTRAINT authority_primary_key PRIMARY KEY (seq_number)
)

前回作成したuserdataテーブルとuser_authorityテーブルは1:多の関係です。
結合するカラムはuserdata.user_idとuser_authority.auth_user_idです。

seq_numberはserial型となっていますが、
エンティティのクラスではint型で扱います。

user_authorityテーブルのデータです。

userdataテーブルのデータです。
(前回とデータは変わっていません)

[Entity]

user_authorityテーブルに対応するエンティティのクラスを作成します。

package jp.glory.persistence.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "user_authority")
public class UserAuthority {

    @Id
    @Column(name = "seq_number")
    private int seqNumber = 0;

    @Column(name = "auth_user_id")
    private String authUserId = null;

    @Column(name = "authority_type")
    private int authorityType = 0;

    // アクセサメソッドは省略
}

UserAuthorityクラスでは特に新しいことはしていません。

前回に作ったUserDataクラスを修正します。

package jp.glory.persistence.entity;

import java.sql.Timestamp;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "userdata")
public class UserData {

    @Id
    @Column(name = "user_id")
    private String userId = null;

    private String name = null;

    @Column(name = "last_update")
    private Timestamp lastUpdate = null;

    @OneToMany
    @JoinColumns({
        @JoinColumn(name = "auth_user_id", referencedColumnName = "user_id")
    })
    private List<UserAuthority> authorityList = null;

    // アクセサメソッドは省略
}

userdataテーブルからuser_authorityテーブルへは
1:多の関係なので、UserDataクラスからUserAuthorityのリストを持ちます。

1:多の場合はjavax.persistence.OneToManyアノテーションを使用します。
OneToMany以外にOneToOne、ManyToOne、ManyToManyアノテーションがあります。

結合するカラムの設定はjavax.persistence.JoinColumnアノテーションを使用します。
今回はJoinColumnsアノテーションの中には
複数のJoinColumnアノテーションの定義が指定できます。
結合するカラムが一つの場合はJoinColumnアノテーションだけの指定で動きます。

JoinColumnアノテーションではname属性を指定します。
結合するカラム名が同じであればname属性だけの指定で動きます。

サンプルではカラム名が異なるので、
name属性とreferencedColumnName属性を指定しています。
name属性には結合先のテーブルのカラム名を、
referencedColumnName属性には結合元のテーブルのカラム名を指定します。

[persistence.xml]

persistence.xmlに今回作成したエンティティクラスを追加します。

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
    xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
    http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">

    <persistence-unit name="blog" transaction-type="JTA">
        <jta-data-source>jdbc/blog</jta-data-source>
        <class>jp.glory.persistence.entity.UserData</class>
        <class>jp.glory.persistence.entity.UserAuthority</class>
    </persistence-unit>
</persistence>
[データ取得]

エンティティクラスのデータを取得する
ManagedBeanは前回のUserListPageクラスを再利用します。

package jp.glory.ui;

import java.util.ArrayList;
import java.util.List;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import jp.glory.persistence.entity.UserData;

@ManagedBean(name = "userListPage")
@RequestScoped
public class UserListPage {

    private List<UserData> userList = null;

    public UserListPage() {

        EntityManagerFactory factory = Persistence.createEntityManagerFactory("blog");
        EntityManager manager = factory.createEntityManager();

        userList = new ArrayList<>();
        userList.add(manager.find(UserData.class, "USER-0001"));
        userList.add(manager.find(UserData.class, "USER-0002"));
        userList.add(manager.find(UserData.class, "USER-0003"));
    }

    // アクセサメソッドは省略
}
[ページ]

ページは今回追加したテーブルの表示処理を追加します。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html">
    <f:view>
        <h:dataTable value="#{userListPage.userList}" var="user">
            <h:column>
                <f:facet name="header">
                    ユーザID
                </f:facet>
                <h:outputText value="#{user.userId}" />
            </h:column>
            <h:column>
                <f:facet name="header">
                    ユーザ名
                </f:facet>
                <h:outputText value="#{user.name}" />
            </h:column>
            <h:column>
                <f:facet name="header">
                    最終更新日
                </f:facet>
                <h:outputText value="#{user.lastUpdate}" >
                    <f:convertDateTime pattern="yyyy/MM/dd HH:mm:ss.SSS" timeZone="JST"/>
                </h:outputText>
            </h:column>
            <h:column>
                <f:facet name="header">
                    権限
                </f:facet>
                <ui:repeat value="#{user.authorityList}" var="authority">
                    <h:outputText value="#{authority.authorityType}" />
                </ui:repeat>
            </h:column>
        </h:dataTable>
    </f:view>
</html>

【実行】

ページにアクセスします。

結合したテーブルのデータが取得できました。