S2JDBC における一対多・多対一の関連と検索

Groovy 1.1 で実行できるようにした S2JDBC の環境(id:fits:20071202)で、一対多・多対一の関連の定義と検索を試してみた。

テーブル定義に使った SQL は以下の通り。EMP テーブルで外部キーを定義している。

DROP TABLE IF EXISTS DEPT;
CREATE TABLE DEPT(ID INT IDENTITY PRIMARY KEY , DEPT_NO INT, DEPT_NAME VARCHAR(50), LOC VARCHAR(255), VERSION_NO INT);

DROP TABLE IF EXISTS EMP;
CREATE TABLE EMP(ID INT IDENTITY PRIMARY KEY , NAME VARCHAR(50), DEPT_ID INT, VERSION_NO INT, FOREIGN KEY(DEPT_ID) REFERENCES DEPT(ID));

Groovy スクリプトは以下の通り。エンティティクラスの定義・新規登録・検索を実施している。

import java.util.List
import javax.persistence.*
import org.seasar.framework.container.SingletonS2Container
import org.seasar.framework.container.factory.SingletonS2ContainerFactory
import org.seasar.extension.jdbc.JdbcManager

@Entity
class Dept {
    @Id
    @GeneratedValue
    Integer id

    Integer deptNo

    String deptName

    String loc

    //一対多の設定(mappedBy で Emp クラスの dept プロパティを指定)
    @OneToMany(mappedBy = "dept")
    List<Emp> empList

    @Version
    Integer versionNo
}

@Entity
class Emp {
    @Id
    @GeneratedValue
    Integer id

    String name

    Integer deptId

    //多対一の設定
    @ManyToOne
    Dept dept

    @Version
    Integer versionNo
}


SingletonS2ContainerFactory.init()

def jdbcManager = SingletonS2Container.getComponent(JdbcManager.class)

//Dept を作成して DB に新規登録
def createDept = {deptNo, deptName ->
    def deptData = new Dept(deptNo : deptNo, deptName : deptName)
    jdbcManager.insert(deptData).execute()
    deptData.id
}

//Emp を作成して DB に新規登録
def createEmp = {name, deptId ->
    def empData = new Emp(name : name, deptId : deptId)
    jdbcManager.insert(empData).execute()
    empData.id
}

def deptId = createDept(1, "部署1")
createDept(2, "部署2")
createDept(3, "部署3")

def empId = createEmp("従業員1", deptId)
createEmp("従業員2", deptId)
createEmp("従業員3", deptId)

println "------ Dept ----------"

//Dept を検索(一対多関連の Emp 情報を含む)
def dept1 = jdbcManager.from(Dept.class).leftOuterJoin("empList").where("id = ?", deptId).getSingleResult()

println "Dept id=${dept1.id}, name=${dept1.deptName}, emp size=${dept1.empList.size}"
dept1.empList.each {
    println " - emp id=${it.id}, name=${it.name}, dept=${it.dept}"
}

println "------ Emp ----------"

//Emp を検索(多対一関連の Dept 情報を含む)
def emp1 = jdbcManager.from(Emp.class).leftOuterJoin("dept").where("id = ?", empId).getSingleResult()

println "Emp id=${emp1.id}, name=${emp1.name}, deptName=${emp1.dept.deptName}, dept.empList.size=${emp1.dept.empList.size}(${emp1.dept.empList[0].name})"

一対多や多対一を検索する際、join 系のメソッド(join、innerJoin、leftOuterJoin)を結合するプロパティを指定して呼び出す。

例えば、Dept の検索で leftOuterJoin("empList") の呼び出しが無いと、取得した Dept オブジェクトの empList プロパティの値は null になる。

なお、上記を実行した結果は以下の通り。

------ Dept ----------
Dept id=1, name=部署1, emp size=3
 - emp id=1, name=従業員1, dept=Dept@e93999
 - emp id=2, name=従業員2, dept=Dept@e93999
 - emp id=3, name=従業員3, dept=Dept@e93999
------ Emp ----------
Emp id=1, name=従業員1, deptName=部署1, dept.empList.size=1(従業員1)