일대일(1:1) 관계 설정하기

Posted at 2009. 8. 27. 16:58 | Posted in Framework/Hibernate
반응형

바로전 포스트에서 아주 기본적인 하이버네이트 매핑하는 걸 했었는데...

이번에는 이 매핑된 클래스끼리 관계 설정하는 것을 해보겠습니다!!

두개의 테이블이 PK(Primary Key)와 FK(Foreign Key)로 관계(Relation)가 형성되어 있는데 ORM(Object-Relational Mapping) 이랍시고 클래스와 매핑 시켰는데 테이블간의 관계를 클래스에서 제대로 사용할 수 없다면 쓰나 마나겠죠... -_-/

먼저 일대일(1:1) 관계를 해봅시다.


Java 1.6.0_15
Eclipse 3.5
Hibernate 3.3.2.GA
Apache Tomcat 6.0.18
MySQL 5.1 (HSQLDB 1.9.0 rc4)



먼저 일단 기본적인 클래스와 매핑 XML 을 만듭니다.(1:1관계가 설정 안된 상태)

Board.java
package com.tistory.antop;

import java.text.SimpleDateFormat;
import java.util.Date;

public class Board {

    private int boardId;
    private String title;
    private String userName;
    private Date writeDate = new Date();

    public Board() { }

    // getter and setter (private setter boardId)
}

Board.hbm.xml
<hibernate-mapping package="com.tistory.antop">
    <class name="Board" table="tbl_board">
        <id name="boardId" column="board_id" length="11">
            <generator class="native" />
        </id>
        <property name="title" length="255" not-null="true" />
        <property name="userName" column="user_name" length="30" not-null="true" />
        <property name="writeDate" column="write_date" type="timestamp" not-null="true" />
    </class>
</hibernate-mapping>

※ 매핑 XML 에 대한 설명은 여기(또는 한글번역본)를 봐주세요~ ㅠ_ㅠ 결고 설명하기 귀찮아서 그러는게 아닝미...


BoardDetail.java
package com.tistory.antop;

public class BoardDetail {

    private int boardId;
    private String email;
    private String contents;
    private Board board;
 
    public BoardDetail() { }

    // getter and setter (private setter boardId)
}

BoardDetail.hbm.xml
<hibernate-mapping package="com.tistory.antop">
    <class name="BoardDetail" table="tbl_board_detail">
        <id name="boardId" column="board_id" type="integer" length="11"></id>
        <property name="email" type="string" length="50" not-null="false" />
        <property name="contents" type="text" not-null="false" />
    </class>
</hibernate-mapping>


hibernate.cfg.xml
<hibernate-configuration>
    <session-factory>
        ...
        ...

        <!-- Mapping -->
        <mapping resource="com/tistory/antop/Board.hbm.xml" />
        <mapping resource="com/tistory/antop/BoardDetail.hbm.xml" />
    </session-factory>
</hibernate-configuration>


따로따로 쓰면 아주 잘 되는 매핑입니다. 현재 상태에서의 테이블은 아래와 같습니다.



1:1 관계를 설정해봅시다.

Board.java 와 BoardDetail.java 에 서로를 참조하는 필드를 만듭니다.

Board.java
public class Board {
    ...
   
    private BoardDetail boardDetail;

    // getter and setter
}

BoardDetail.java
public class BoardDetail {
    ....

    private Board board;

    // getter and setter
}


매핑 XML 에서 Board와 BoardDetail 의 1:1 관계를 설정합니다.

Board.hbm.xml
<hibernate-mapping package="com.tistory.antop">
    <class name="Board" table="tbl_board">
        ...
        
        <!-- name: 관계를 맺을 클래스를 참조하는 필드 이름 -->
        <!-- class: 관계를 맺을 클래스 이름(패키지 포함) -->
        <!-- cascade: 삭제나 업데이트 시 관계가 맺어진(?) 테이블도 적용할지 하는 설정 -->
        <one-to-one name="boardDetail" class="com.tistory.antop.BoardDetail" cascade="all" />
     </class>
</hibernate-mapping>

BoardDetail.hbm.xml
<hibernate-mapping package="com.tistory.antop">
    <class name="BoardDetail" table="tbl_board_detail">
        <!-- Board 의 pk 번호를 따라가게 설정 -->
        <id name="boardId" column="board_id" type="integer" length="11">
            <generator class="foreign">
                <param name="property">board</param>
            </generator>
        </id>

        ...
  
        <!-- name: 관계를 맺을 클래스를 참조하는 필드 이름 -->
        <!-- class : 관계를 맺을 클래스 이름(패키지 포함) -->
        <!-- constrained: 매핑된 테이블의 PK에 대한 FK constraint가 연관된 클래스의 테이블을 참조하는지 여부를 지정 -->
        <one-to-one name="board" class="com.tistory.antop.Board" constrained="true" />
    </class>
</hibernate-mapping>


보면 알겠지만... 속성들이 DDL에 나오는 것들이랑 거의 비슷 합니다. 촉이 좋으면 금방 알 것입니다. +_+;

hibernate.cfg.xml 에서 hbm2ddl.auto을 설정해서 만들어진 DDL 을 보면 PK, FK 로 1:1 관계가 생성된걸 볼 수 있습니다.

hibernate.cfg.xml
<hibernate-configuration>
    <session-factory>
        ...

        <!-- 최초 시작(startup) 시 테이블을 새로 생성(drop and re-create database schema) -->
        <property name="hbm2ddl.auto">create</property>

        ...

    </session-factory>
</hibernate-configuration>


DDL(Data Definition Language) - MySQL 5.1 기준
CREATE TABLE `tbl_board` (
  `board_id` INTEGER(11) NOT NULL AUTO_INCREMENT,
  `title` VARCHAR(255) COLLATE utf8_general_ci NOT NULL DEFAULT '',
  `user_name` VARCHAR(30) COLLATE utf8_general_ci NOT NULL DEFAULT '',
  `write_date` DATETIME NOT NULL,
  PRIMARY KEY (`board_id`)

)ENGINE=InnoDB
AUTO_INCREMENT=1 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';

--

CREATE TABLE `tbl_board_detail` (
  `board_id` INTEGER(11) NOT NULL,
  `email` VARCHAR(50) COLLATE utf8_general_ci DEFAULT NULL,
  `contents` LONGTEXT,
  PRIMARY KEY (`board_id`),
  KEY `FK658F66AB607D6F39` (`board_id`),
  CONSTRAINT `FK658F66AB607D6F39` FOREIGN KEY (`board_id`) REFERENCES `tbl_board` (`board_id`)

)ENGINE=InnoDB
CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';




간단하게 CRUD 를 만들었습니다.




※ _mysql 과 _hsqldb 는 hibernate.cfg.xml 의 jdbc 설정과 lib 의 jdbc 라이브러만 다릅니다. 소스는 똑같습니다.

MySQL 도 귀찮다! 하시면 hsqldb 로 만들걸 해보세요~ +_+


중요한 부분은 저장할 때 서로를 참조 시켜주는 겁니다.

proc.jsp
...

Session sess = HibernateUtil.getCurrentSession();
Transaction tx = sess.beginTransaction();

// 등록
if("write".equals(query)) {
    String title = request.getParameter("title");
    String userName = request.getParameter("userName");
    String email = request.getParameter("email");
    String contents = request.getParameter("contents");

    Board board = new Board();
    board.setTitle(title);
    board.setUserName(userName);
 
    BoardDetail boardDetail = new BoardDetail();
    boardDetail.setEmail(email);
    boardDetail.setContents(contents);
 
    // 게시물과 게시물상세의 1:1 관계 설정
    board.setBoardDetail(boardDetail);
    boardDetail.setBoard(board);
 
    sess.save(board);        // Board 저장 (insert 쿼리)
}

...

tx.commit();        // BoardDetail 저장 (insert 쿼리)
HibernateUtil.closeSession();


Board는 sess.save(baord); 에서 저장 하는데, BoardDetail은 tx.commit(); 에서 저장을 하네요... 음... ^O^




참고 사이트
http://javacan.tistory.com/entry/102
http://javacan.tistory.com/entry/103
http://javacan.tistory.com/entry/104
http://javacan.tistory.com/entry/105

반응형

'Framework > Hibernate' 카테고리의 다른 글

PK 두개 이상시 매핑  (2) 2009.12.24
Reverse Engineering  (0) 2009.12.24
Hibernate 시작하기  (0) 2009.12.23
Criteria 사용하여 질의 하기 #2  (1) 2009.10.03
Criteria 사용하여 질의 하기 #1  (4) 2009.09.10
다대다(n:m) 관계 설정하기  (0) 2009.09.02
일대다(1:n) 관계 설정하기  (1) 2009.08.31
하이버네이트(Hibernate) 사용하기  (6) 2009.08.24
//