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

Posted at 2009. 8. 31. 16:22 | Posted in Framework/Hibernate
반응형
전 포스핑에서 1:1 관계를 설정해봤습니다.

테스트 업무는 고객(cutomer)이 문의(support)를 올리고, 관리자가 그 문의에 답변(reply)을 다는 업무입니다.

고객은 문의를 여러번 할 수 있고, 관리자는 그 문의에 여러번 답변할  수 있습니다.


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)



먼저 아무 관계가 없는 매핑을 만들어 봅시다.

Customer.java
package com.tistory.antop;

public class Customer {

    private String id;
    private String name;
    private String pwd;
    private String tel;

    // construct, getter, setter
}

Customer.hbm.xml
<hibernate-mapping package="com.tistory.antop">
    <class name="Customer" table="tbl_customers">
        <id name="id" length="20" />
        <property name="pwd" column="password" length="20" not-null="true" />
        <property name="name" length="30" not-null="true" />
        <property name="tel" length="13" not-null="false" />
    </class>
</hibernate-mapping>


Support.java
package com.tistory.antop;

public class Support {

    private int id;
    private String title;
    private String contents;

    // construct, getter, setter (private setter id)
}

Support.hbm.xml
<hibernate-mapping package="com.tistory.antop">
    <class name="Support" table="tbl_supprots">
        <id name="id" column="support_id">
            <generator class="native" />
        </id>
        <property name="title" length="255" not-null="true" />
        <property name="contents" type="text" />
    </class>
</hibernate-mapping>


Reply.java
package com.tistory.antop;

public class Reply {

    private int seq;
    private String reply;
 
    // construct, getter, setter (private setter seq)
}

Reply.hbm.xml
<hibernate-mapping package="com.tistory.antop">
    <class name="Reply" table="tbl_replays">
        <id name="seq">
            <generator class="native" />
        </id>
        <property name="reply" type="text" not-null="true" />
    </class>
</hibernate-mapping>


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

        <!-- Mapping -->
        <mapping resource="com/tistory/antop/Customer.hbm.xml" />
        <mapping resource="com/tistory/antop/Support.hbm.xml" />
        <mapping resource="com/tistory/antop/Reply.hbm.xml" />

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



아무런 관계(릴레이션)가 없는 테이블 3개가 매핑 되었습니다.



이제 1:n 관계를 설정 합시다.

1:1에서와 마찬가지로 서로 참조를 시켜야 합니다.
 
db 에서는 1:n 관계를 1이 되는쪽의 PK 와 n 이 되는쪽의 FK를 지정하여 관계를 설정해주고,
 
클래스로 구현하면 1이 되는 클래스 필드가 n이 되는 클래스를 n개 만큼 참조하고 있어야 합니다.

반대로 n쪽의 클래스는 1이 되는 클래스를 참조하고 있어야겠죠?


먼저 고객(customer)과 문의(support)의 1:n 관계를 설정 해봅시다.


관계를 맺을 수 있는 필드와 사용할 적절한 메소드를 추가합니다.

Customer.java
public class Customer {
    ...

    // customer 1:n support 관계를 가지는 필드
    private Set<Support> supports = new HashSet<Support>();

    public Set<Reply> getReplys() {
        return replys;
    }

    private void setReplys(Set<Reply> replys) {
        this.replys = replys;
    }

    // 문의 추가
    public void addSupport(Support support) {
        if(getSupports() == null) {
            setSupports(new HashSet<Support>());
        }
        // customer -> support 참조
        getSupports().add(support);
        // support -> customer 참조
        support.setCustomer(this);
    }
 
    // 문의 삭제
    public void delSupport(Support support) {
        getSupports().remove(support);
    }
 
    // 문의 비우기
    public void clearSupports() {
        getSupports().clear();
    }
}

Customer.hbm.xml
<hibernate-mapping package="com.tistory.antop">
    <class name="Customer" table="tbl_customers">
        ...

        <!-- customer 1:n support -->
        <set name="supports" inverse="true" cascade="all-delete-orphan">
            <key column="customer_id" />
            <one-to-many class="com.tistory.antop.Support" />
        </set>
    </class>
}

Customer 와 Support 의 1:n 관계에서 Support는 콜랙션(Collection) 형태로 참조됩니다.

Set, List, Bag, Map 등등 있는데 자세한건 여기에서 확인을... -0-

 -= <set></set> : java.util.Set 타입으로 정의합니다.
   - name : java.util.Set 타입의 필드명입니다. (Customer.java의 "private Set<Support> supports")
   - inverse : 객체간 관계의 책임을 어디에 둘지에 대한 옵션을 정의하기 위한 속성입니다.
                   즉, 한 쪽은 owner의 역할을 맡기고, 다른 한 쪽에는 sub의 역할을 맡기기 위함입니다.
   - cascade : 부모 객체에 대한 CUD를 자식 객체에도 전이할지에 대한 옵션을 정의하기 위한 속성입니다.
 -= <key column="..." /> : FK(Foreign Key)를 명시합니다. (Support 쪽의 FK)
 -= <on-to-many class="..." /> : 관계를 맺는 클래스명(패키지명포함)을 명시합니다.


Support.java
public class Support {
    ...
    // customer 1:n support 관계를 가지는 필드
    private Customer customer;
   
    public Customer getCustomer() {
        return customer;
    }

    private void setCustomer(Customer customer) {
        this.customer = customer;
    }

    // 답변 추가
    public void addReply(Reply reply) {
        if(getReplys() == null) {
            setReplys(new HashSet<Reply>());
        }
        // support -> reply 참조
        getReplys().add(reply);
        // reply -> support 참조
        reply.setSupport(this);
    }
 
    // 답변 삭제
    public void delReply(Reply reply) {
        getReplys().remove(reply);
    }
 
    // 답변 비우기
    public void clear() {
        getReplys().clear();
    }
}

Support.hbm.xml
<hibernate-mapping package="com.tistory.antop">
    <class name="Support" table="tbl_supprots">
         ...

        <!-- customer 1:n support -->
        <many-to-one name="customer" column="customer_id" class="com.tistory.antop.Customer" />
    </class>
</hibernate-mapping>

Support 쪽에서는 그냥 customer 하나만 참조하면 됩니다.


이제 문의(support)와 답변(reply)도 1:n 관계를 설정합시다! +_+/

Support.java
public class Support {
    ...

    // support 1:n reply 관계를 가지는 필드
    private Set<Reply> replys = new HashSet<Reply>();

    public Set<Reply> getReplys() {
        return replys;
    }

    private void setReplys(Set<Reply> replys) {
        this.replys = replys;
    }
}

Support.hbm.xml
<hibernate-mapping package="com.tistory.antop">
    <class name="Support" table="tbl_supprots">
        ...

        <!-- support 1:n reply -->
        <set name="replys" inverse="true" cascade="all-delete-orphan">
            <key column="support_id" />
            <one-to-many class="com.tistory.antop.Reply" />
        </set>
    </class>
</hibernate-mapping>


Reply.java
public class Reply {
    ...

    // support 1:n reply 관계를 가지는 필드
    private Support support;

    public Support getSupport() {
        return support;
    }

    public void setSupport(Support support) {
        this.support = support;
    }
}

Reply.hbm.xml
<hibernate-mapping package="com.tistory.antop">
    <class name="Reply" table="tbl_replays">
        ...

        <!-- support 1:n reply -->
        <many-to-one name="support" column="support_id" class="com.tistory.antop.Support" />
    </class>
</hibernate-mapping>


이제 문의(support)와 답변(reply)의 1:n 관계도 설정 되었습니다.




이제 CRUD 해야졍.... 배보다 배꼽이 더 크네여 아오~

이번에는 조금 제대로 만들어 보았습니다... (아주 조금입니다... 조ㄱㅡ..)

진짜 배보다 배꼽이 더 켜졌네요;;;





참고 사이트
http://docs.jboss.org/hibernate/stable/core/reference/en/html/associations.html
http://dev.anyframejava.org/anyframe/doc/core/3.1.0/corefw/guide/hibernate-persistence-mapping-association.html
http://javacan.tistory.com/entry/106


반응형

'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:1) 관계 설정하기  (0) 2009.08.27
하이버네이트(Hibernate) 사용하기  (6) 2009.08.24
//