mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-03-01 07:19:15 +00:00
git-svn-id: https://svn.jboss.org/repos/hibernate/core/branches/Branch_3_2@11779 1b8cb986-b30d-0410-93ca-fae66ebed9b2
1159 lines
54 KiB
XML
1159 lines
54 KiB
XML
<chapter id="collections">
|
|
<title>콜렉션 매핑</title>
|
|
|
|
<sect1 id="collections-persistent" revision="3">
|
|
<title>영속 콜렉션들</title>
|
|
|
|
<para>
|
|
예를 들어 Hibernate는 영속 콜렉션-값을 가진 필드들이 인터페이스 타입으로서 선언될 것을 필요로 한다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[public class Product {
|
|
private String serialNumber;
|
|
private Set parts = new HashSet();
|
|
|
|
public Set getParts() { return parts; }
|
|
void setParts(Set parts) { this.parts = parts; }
|
|
public String getSerialNumber() { return serialNumber; }
|
|
void setSerialNumber(String sn) { serialNumber = sn; }
|
|
}]]></programlisting>
|
|
|
|
<para>
|
|
실제 인터페이스는 <literal>java.util.Set</literal>, <literal>java.util.Collection</literal>,
|
|
<literal>java.util.List</literal>, <literal>java.util.Map</literal>, <literal>java.util.SortedSet</literal>,
|
|
<literal>java.util.SortedMap</literal> 또는 당신이 좋아하는 어떤 것일 수 있다!(여기서 "당신이 좋아하는 어떤 것"이란
|
|
당신이 <literal>org.hibernate.usertype.UserCollectionType</literal>에 대한 구현을 작성해야 함을 의미한다.)
|
|
</para>
|
|
|
|
<para>
|
|
우리가 <literal>HashSet</literal>의 인스턴스를 가진 인스턴스 변수를 초기화 시켰던 방법을 주목하라. 이것은 새로이
|
|
초기화 된(비-영속) 인스턴스들을 가진 콜렉션 값 프로퍼티들을 초기화 시키는 최선의 방법이다. 당신이 -예를 들어
|
|
<literal>persist()</literal>를 호출하여- 인스턴스를 영속화 시킬 때 Hibernate는 실제로 <literal>HashSet</literal>을
|
|
<literal>Set</literal>에 대한 Hibernate 자신의 구현의 인스턴스로 대체시킬 것이다. 다음과 같은 오류들을 관찰하라:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[Cat cat = new DomesticCat();
|
|
Cat kitten = new DomesticCat();
|
|
....
|
|
Set kittens = new HashSet();
|
|
kittens.add(kitten);
|
|
cat.setKittens(kittens);
|
|
session.persist(cat);
|
|
kittens = cat.getKittens(); // Okay, kittens collection is a Set
|
|
(HashSet) cat.getKittens(); // Error!]]></programlisting>
|
|
|
|
<para>
|
|
Hibernate에 의해 도입된 영속 콜렉션들은 인터페이스 타입에 따라 <literal>HashMap</literal>, <literal>HashSet</literal>,
|
|
<literal>TreeMap</literal>, <literal>TreeSet</literal> 또는 <literal>ArrayList</literal>와 같이 행위한다.
|
|
</para>
|
|
|
|
<para>
|
|
콜렉션 인스턴스들은 value 타입들을 가진 통상의 특징을 갖는다. 그것들은 영속 객체에 의해 참조될 때 자동적으로 영속화 되고
|
|
참조 해제될 때 자동적으로 삭제된다. 만일 하나의 콜렉션이 하나의 영속 객체로부터 또 다른 영속 객체로 전달될 때, 그것의 요소들은
|
|
하나의 테이블로부터 다른 테이블로 이동될 수 있다. 두 개의 엔티티들은 동일한 콜렉션 인스턴스에 대한 참조를 공유하지 않는다.
|
|
기본 관계형 모형 때문에 콜렉션 값 프로퍼티들은 null 값 의미들을 지원하지 않는다; Hibernate는 null 콜렉션 참조와 공백의
|
|
콜렉션 사이를 구별 짓지 않는다.
|
|
</para>
|
|
|
|
<para>
|
|
당신은 이것의 어떤 것에 대해 너무 많이 걱정하지 않아도 될 것이다. 당신이 통상의 자바 콜렉션들을 사용하는 것과 동일한 방법으로
|
|
영속 콜렉션들을 사용하라. 단지 당신이 양방향 연관관계들에 대한 의미를 확실히 이해하도록 하라(나중에 논의됨).
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="collections-mapping" revision="4">
|
|
<title>콜렉션 매핑들</title>
|
|
|
|
<para>
|
|
콜렉션을 매핑하는데 사용되는 Hiberante 매핑 요소는 인터페이스의 타입에 의존한다. 예를 들어<literal><set></literal>
|
|
요소는 <literal>Set</literal> 타입의 매핑 프로퍼티들에 사용된다
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<class name="Product">
|
|
<id name="serialNumber" column="productSerialNumber"/>
|
|
<set name="parts">
|
|
<key column="productSerialNumber" not-null="true"/>
|
|
<one-to-many class="Part"/>
|
|
</set>
|
|
</class>]]></programlisting>
|
|
|
|
<para>
|
|
<literal><set></literal>과는 별도로, 또한 <literal><list></literal>, <literal><map></literal>,
|
|
<literal><bag></literal>, <literal><array></literal>, 그리고 <literal><map></literal>
|
|
매핑 요소들이 존재한다. <literal><map></literal> 요소가 대표적이다:
|
|
</para>
|
|
|
|
<programlistingco>
|
|
<areaspec>
|
|
<area id="mappingcollection1" coords="2 65"/>
|
|
<area id="mappingcollection2" coords="3 65"/>
|
|
<area id="mappingcollection3" coords="4 65"/>
|
|
<area id="mappingcollection4" coords="5 65"/>
|
|
<area id="mappingcollection5" coords="6 65"/>
|
|
<area id="mappingcollection6" coords="7 65"/>
|
|
<area id="mappingcollection7" coords="8 65"/>
|
|
<area id="mappingcollection8" coords="9 65"/>
|
|
<area id="mappingcollection9" coords="10 65"/>
|
|
<area id="mappingcollection10" coords="11 65"/>
|
|
<area id="mappingcollection11" coords="12 65"/>
|
|
<area id="mappingcollection12" coords="13 65"/>
|
|
<area id="mappingcollection13" coords="14 65"/>
|
|
<area id="mappingcollection14" coords="15 65"/>
|
|
</areaspec>
|
|
<programlisting><![CDATA[<map
|
|
name="propertyName"
|
|
table="table_name"
|
|
schema="schema_name"
|
|
lazy="true|extra|false"
|
|
inverse="true|false"
|
|
cascade="all|none|save-update|delete|all-delete-orphan|delete-orphan"
|
|
sort="unsorted|natural|comparatorClass"
|
|
order-by="column_name asc|desc"
|
|
where="arbitrary sql where condition"
|
|
fetch="join|select|subselect"
|
|
batch-size="N"
|
|
access="field|property|ClassName"
|
|
optimistic-lock="true|false"
|
|
mutable="true|false"
|
|
node="element-name|."
|
|
embed-xml="true|false"
|
|
>
|
|
|
|
<key .... />
|
|
<map-key .... />
|
|
<element .... />
|
|
</map>]]></programlisting>
|
|
<calloutlist>
|
|
<callout arearefs="mappingcollection1">
|
|
<para>
|
|
<literal>name</literal> 콜렉션 프로퍼티 이름
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mappingcollection2">
|
|
<para>
|
|
<literal>table</literal> (옵션 - 디폴트는 프로퍼티 이름)
|
|
콜렉션 테이블의 이름(one-to-many 연관관계들에 대해서는 사용되지 않음)
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mappingcollection3">
|
|
<para>
|
|
<literal>schema</literal> (옵션)
|
|
루트 요소 상에 선언된 스키마를 오버라이드 시키는 테이블 스키마의 이름
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mappingcollection4">
|
|
<para>
|
|
<literal>lazy</literal> (옵션 - 디폴트는 <literal>true</literal>)는
|
|
lazy 페칭을 사용 불가능하도록 하고 그 연관이 항상 eagerly 페치됨을 지정하는데 , 또는 대부분의
|
|
연산들이 콜렉션을 초기화시키지 않는 곳에서 "extra-lazy" 페칭을 이용 가능하도록 하는데(매우 큰 콜렉션들에
|
|
적당함) 사용될 수 있다
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mappingcollection5">
|
|
<para>
|
|
<literal>inverse</literal> (옵션 - 디폴트는 <literal>false</literal>)
|
|
이 콜렉션을 양방향 연관관계의 "inverse" 끝(end)으로 표시한다
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mappingcollection6">
|
|
<para>
|
|
<literal>cascade</literal> (옵션 - 디폴트는 <literal>none</literal>)
|
|
오퍼레이션들이 자식 엔티티들에 대해 케스케이드하는 것을 이용 가능하게 한다
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mappingcollection7">
|
|
<para>
|
|
<literal>sort</literal> (옵션)
|
|
<literal>natural</literal> 정렬 순서로 정렬된(sorted) 콜렉션 또는 주어진 comparator 클래스를 지정한다
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mappingcollection8">
|
|
<para>
|
|
<literal>order-by</literal> (옵션, JDK1.4에서만)
|
|
<literal>asc</literal> 또는 <literal>desc</literal> 옵션과 함께 <literal>Map</literal>,
|
|
<literal>Set</literal> 또는 bag의 반복 순서를 정의하는 테이블 컬럼(또는 컬럼들)을 지정한다
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mappingcollection9">
|
|
<para>
|
|
<literal>where</literal> (옵션)
|
|
콜렉션을 검색하거나 제거할 때 사용될 임의적인 SQL <literal>WHERE</literal> 조건을 지정한다
|
|
(콜렉션이 오직 이용 가능한 데이터의 부분집합 만을 포함할 경우에 유용하다)
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mappingcollection10">
|
|
<para>
|
|
<literal>fetch</literal> (옵션, 디폴트는 <literal>select</literal>)
|
|
outer-join 페칭, sequential select 페칭, 그리고 sequential subselect 페칭 사이에서 선택하라.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mappingcollection11">
|
|
<para>
|
|
<literal>batch-size</literal> (옵션, 디폴트는 <literal>1</literal>)
|
|
이 콜렉션의 lazily fetching 인스턴스에 대해 "배치 사이즈"를 지정하라.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mappingcollection12">
|
|
<para>
|
|
<literal>access</literal> (옵션 - 디폴트는 <literal>property</literal>):
|
|
Hibernate가 콜렉션 프로퍼티 값에 접근하는데 사용할 방도.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mappingcollection13">
|
|
<para>
|
|
<literal>optimistic-lock</literal> (옵션 - 디폴트는 <literal>true</literal>):
|
|
콜렉션의 상태에 대한 변경들이 소유하는 엔티티의 버전의 증가로 귀결될 것인지를 지정한다.
|
|
(one to many 연관들에 대해, 이 설정을 사용 불가능하게 하는 것이 종종 합당하다.)
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mappingcollection14">
|
|
<para>
|
|
<literal>mutable</literal> (옵션 - 디폴트는 <literal>true</literal>):
|
|
<literal>false</literal> 값은 콜렉션의 요소들이 결코 변경되지 않음을 지정한다.
|
|
(몇몇 경우들에서 마이너 퍼포먼스 최적화).
|
|
</para>
|
|
</callout>
|
|
</calloutlist>
|
|
</programlistingco>
|
|
|
|
<sect2 id="collections-foreignkeys" >
|
|
<title>콜렉션 foreign 키들</title>
|
|
|
|
<para>
|
|
콜렉션 인스턴스들은 그 콜렉션을 소유하는 엔티티의 foreign 키에 의해 데이터베이스 내에서 구별지워진다. 이 foreign 키는
|
|
그 콜렉션 테이블의 <emphasis>콜렉션 키 컬럼</emphasis> (또는 컬럼들)로서 참조된다. 그 콜렉션 키 컬럼은
|
|
<literal><key></literal> 요소에 의해 매핑된다.
|
|
</para>
|
|
|
|
<para>
|
|
foreign 키 컬럼에 대한 null 허용 가능 컨스트레인트가 존재할 수 있다. 대부분의 콜렉션들에 대해, 이것이 당연히 수반된다.
|
|
단방향 one to many 연관들의 경우, foreign 키는 디폴트로 null 허용 가능하여서, 당신은 <literal>not-null="true"</literal>를
|
|
지정할 필요가 있을 수 있다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<key column="productSerialNumber" not-null="true"/>]]></programlisting>
|
|
|
|
<para>
|
|
foreign 키 컨스트레인트는 <literal>ON DELETE CASCADE</literal>를 사용할 수도 있다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<key column="productSerialNumber" on-delete="cascade"/>]]></programlisting>
|
|
|
|
<para>
|
|
<literal><key></literal> 요소에 대한 전체 정의는 앞 장을 보라.
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="collections-elements" >
|
|
<title>콜렉션 요소들</title>
|
|
|
|
<para>
|
|
콜렉션들은 모든 기본 타입들, 컴포넌트들, 그리고 물론 다른 엔티티들에 대한 참조들을 포함하여 거의 대부분의
|
|
어떤 다른 Hibernate 타입을 포함할 수도 있다. 이것은 중요한 구분이다: 콜렉션 내에 있는 객체는 "값(value)"
|
|
의미로 처리될 수도 있거나(그것의 생명주기는 콜렉션 소유자에 의존한다) 그것은 그것 자신의 생명주기를 가진
|
|
또 다른 엔티티에 대한 참조일 수 있다. 후자의 경우, 두 개의 객체들 사이의 "링크" 만이 그 콜렉션에 의해 소유된
|
|
상태로 간주된다.
|
|
</para>
|
|
|
|
<para>
|
|
포함된 타입은 콜렉션 요소 타입으로서 불려진다. 콜렉션 요소들은 <literal><element></literal>
|
|
또는 <literal><composite-element></literal>에 의해 매핑되거나, 엔티티 참조들의 경우에
|
|
<literal><one-to-many></literal> 또는 <literal><many-to-many></literal>로서
|
|
매핑된다. 앞의 두 개는 value 의미를 가진 요소들을 매핑시키고, 뒤의 두개는 엔티티 연관들을 매핑하는데 사용된다.
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="collections-indexed">
|
|
<title>인덱싱 된 콜렉션들</title>
|
|
|
|
<para>
|
|
set 과 bag 의미들을 가진 것들을 제외하면, 모든 콜렉션 매핑들은 콜렉션 테이블 내에 <emphasis>인덱스 컬럼</emphasis>-
|
|
배열 인덱스, 또는 <literal>List</literal> 인덱스 또는 <literal>Map</literal> 키로 매핑되는 컬럼-을 필요로 한다.
|
|
<literal>Map</literal>의 인덱스는 <literal><map-key></literal>로 매핑된, 어떤 기본 타입일 수 있고,
|
|
그것은 <literal><map-key-many-to-many></literal>로 매핑된 엔티티 참조일 수 있거나, 그것은
|
|
<literal><composite-map-key></literal>로 매핑된 composite 타입일 수 있다. 배열 또는 리스트의 인덱스는
|
|
항상 <literal>integer</literal> 타입이고 <literal><list-index></literal> 요소를 사용하여 매핑된다.
|
|
매핑된 컬럼은 순차적인 정수들을 포함한다(디폴트로 0에서 시작하는 번호가 붙여짐).
|
|
</para>
|
|
|
|
<programlistingco>
|
|
<areaspec>
|
|
<area id="index1" coords="2 45"/>
|
|
<area id="index2" coords="3 45"/>
|
|
</areaspec>
|
|
<programlisting><![CDATA[<list-index
|
|
column="column_name"
|
|
base="0|1|..."/>]]></programlisting>
|
|
<calloutlist>
|
|
<callout arearefs="index1">
|
|
<para>
|
|
<literal>column_name</literal> (필수):
|
|
콜렉션 인덱스 값들을 보관하는 컬럼의 이름.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="index1">
|
|
<para>
|
|
<literal>base</literal> (옵션, 디폴트는 <literal>0</literal>):
|
|
리스트 또는 배열의 첫 번째 요소에 대응하는 인덱스 컬럼의 값.
|
|
</para>
|
|
</callout>
|
|
</calloutlist>
|
|
</programlistingco>
|
|
|
|
<programlistingco>
|
|
<areaspec>
|
|
<area id="mapkey1" coords="2 45"/>
|
|
<area id="mapkey2" coords="3 45"/>
|
|
<area id="mapkey3" coords="4 45"/>
|
|
</areaspec>
|
|
<programlisting><![CDATA[<map-key
|
|
column="column_name"
|
|
formula="any SQL expression"
|
|
type="type_name"
|
|
node="@attribute-name"
|
|
length="N"/>]]></programlisting>
|
|
<calloutlist>
|
|
<callout arearefs="mapkey1">
|
|
<para>
|
|
<literal>column</literal> (옵션):
|
|
콜렉션 인덱스 값들을 보관하는 컬럼의 이름.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mapkey2">
|
|
<para>
|
|
<literal>formula</literal> (옵션):
|
|
map의 키를 평가하는데 사용되는 SQL formula.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="mapkey3">
|
|
<para>
|
|
<literal>type</literal> (필수): The type of the map 키들의 타입
|
|
</para>
|
|
</callout>
|
|
</calloutlist>
|
|
</programlistingco>
|
|
|
|
<programlistingco>
|
|
<areaspec>
|
|
<area id="indexmanytomany1" coords="2 45"/>
|
|
<area id="indexmanytomany2" coords="3 45"/>
|
|
<area id="indexmanytomany3" coords="3 45"/>
|
|
</areaspec>
|
|
<programlisting><![CDATA[<map-key-many-to-many
|
|
column="column_name"
|
|
formula="any SQL expression"
|
|
class="ClassName"
|
|
/>]]></programlisting>
|
|
<calloutlist>
|
|
<callout arearefs="indexmanytomany1">
|
|
<para>
|
|
<literal>column</literal> (옵션):
|
|
콜렉션 인덱스 값들에 대한 foreign 키 컬럼의 이름.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="indexmanytomany2">
|
|
<para>
|
|
<literal>formula</literal> (옵션):
|
|
map의 foreign 키를 평가하는데 사용되는 SQL formula.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="indexmanytomany3">
|
|
<para>
|
|
<literal>class</literal> (필수): map 키로서 사용되는 엔티티 클래스.
|
|
</para>
|
|
</callout>
|
|
</calloutlist>
|
|
</programlistingco>
|
|
|
|
|
|
<para>
|
|
만일 당신의 테이블이 인덱스 컬럼을 가지 않고, 당신이 여전히 프로퍼티 타입으로서 <literal>List</literal>를 사용하고자
|
|
원할 경우, 당신은 그 프로퍼티를 Hibernate <emphasis><bag></emphasis>으로서 매핑해야 한다. bag이
|
|
데이터베이스로부터 검색될 때 그것은 그것의 순서를 보유하지 않지만, 그것은 선택적으로 정렬(sorting)되거나 ordering될
|
|
수도 있다.
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<para>
|
|
많은 공통된 관계형 모형들을 다루는, 콜렉션들에 대해 생성될 수 있는 매핑들의 영역이 꽤 존재한다. 여러가지 매핑 선언들이 데이터베이스
|
|
테이블들로 변환되는 방법을 당신이 느끼려면 스키마 생성 도구로 실험할 것을 우리는 제안한다.
|
|
</para>
|
|
|
|
<sect2 id="collections-ofvalues" revision="2">
|
|
<title>값들을 가진 콜렉션들과 many-to-many 연관들</title>
|
|
|
|
<para>
|
|
어떤 값들을 가진 콜렉션 또는 many-to-many 연관은 foreign 키 컬럼이나 컬럼들, <emphasis>콜렉션 요소 컬럼</emphasis>이나
|
|
컬럼들 그리고 가능하면 인덱스 컬럼들이나 컬럼들을 가진 전용 <emphasis>콜렉션 테이블</emphasis>을 필요로 한다.
|
|
</para>
|
|
|
|
<para>
|
|
값들을 가진 콜렉션의 경우, 우리는 <literal><element></literal> 태그를 사용한다.
|
|
</para>
|
|
|
|
<programlistingco>
|
|
<areaspec>
|
|
<area id="element1b" coords="2 50"/>
|
|
<area id="element2b" coords="3 50"/>
|
|
<area id="element3b" coords="4 50"/>
|
|
</areaspec>
|
|
<programlisting><![CDATA[<element
|
|
column="column_name"
|
|
formula="any SQL expression"
|
|
type="typename"
|
|
length="L"
|
|
precision="P"
|
|
scale="S"
|
|
not-null="true|false"
|
|
unique="true|false"
|
|
node="element-name"
|
|
/>]]></programlisting>
|
|
<calloutlist>
|
|
<callout arearefs="element1b">
|
|
<para>
|
|
<literal>column</literal> (옵션): 콜렉션 요소 값들을 소유하는 컬럼의 이름.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="element2b">
|
|
<para>
|
|
<literal>formula</literal> (옵션): 요소를 평가하는데 사용되는 SQL formula.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="element3b">
|
|
<para>
|
|
<literal>type</literal> (필수): 콜렉션 요소의 타입.
|
|
</para>
|
|
</callout>
|
|
</calloutlist>
|
|
</programlistingco>
|
|
|
|
<para>
|
|
<emphasis>many-to-many association</emphasis> 연관은 <literal><many-to-many></literal> 요소를
|
|
사용하여 지정된다.
|
|
</para>
|
|
|
|
<programlistingco>
|
|
<areaspec>
|
|
<area id="manytomany1" coords="2 60"/>
|
|
<area id="manytomany2" coords="3 60"/>
|
|
<area id="manytomany3" coords="4 60"/>
|
|
<area id="manytomany4" coords="5 60"/>
|
|
<area id="manytomany5" coords="6 60"/>
|
|
<area id="manytomany6" coords="7 60"/>
|
|
<area id="manytomany7" coords="8 60"/>
|
|
<area id="manytomany8" coords="9 60"/>
|
|
</areaspec>
|
|
<programlisting><![CDATA[<many-to-many
|
|
column="column_name"
|
|
formula="any SQL expression"
|
|
class="ClassName"
|
|
fetch="select|join"
|
|
unique="true|false"
|
|
not-found="ignore|exception"
|
|
entity-name="EntityName"
|
|
property-ref="propertyNameFromAssociatedClass"
|
|
node="element-name"
|
|
embed-xml="true|false"
|
|
/>]]></programlisting>
|
|
<calloutlist>
|
|
<callout arearefs="manytomany1">
|
|
<para>
|
|
<literal>column</literal> (옵션): 요소 foreign 키 컬럼의 이름.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="manytomany2">
|
|
<para>
|
|
<literal>formula</literal> (옵션): 요소 foreign 키 값을 평가하는데 사용되는 SQL formula.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="manytomany3">
|
|
<para>
|
|
<literal>class</literal> (필수): 연관된 클래스의 이름.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="manytomany4">
|
|
<para>
|
|
<literal>fetch</literal> (옵션 - 디폴트는 <literal>join</literal>):
|
|
이 연관에 대해 outer-join 페칭 또는 sequential select 페칭을 이용 가능하게 만든다. 이것은 특별한 경우이다;
|
|
엔티티 그리고 다른 엔티티들과 그것의 many-to-many 관계들에 대한 (하나의 <literal>SELECT</literal>
|
|
내에서) 전체 eager 페칭의 경우, 당신은 콜렉션 그 자체에 대해서 뿐만 아니라 내포된 요소 <literal><many-to-many></literal>
|
|
상의 이 속성에 대해 <literal>join</literal> 페칭을 이용 가능하게 할 것이다.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="manytomany5">
|
|
<para>
|
|
<literal>unique</literal> (옵션):
|
|
foreign-key 컬럼에 대한 유일 컨스트레인트의 DDL 생성을 가능하도록 한다. 이것은 연관 다중성
|
|
(association multiplicity)을 효율적으로 one to many로 만든다.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="manytomany6">
|
|
<para>
|
|
<literal>not-found</literal> (옵션 - 디폴트는 <literal>exception</literal>):
|
|
누락된 행들을 참조하는 foreign 키들이 어떻게 처리될 것인지를 지정한다:
|
|
<literal>ignore</literal>는 누락된 한 행을 한 개의 연관으로 다룰 것이다.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="manytomany7">
|
|
<para>
|
|
<literal>entity-name</literal> (옵션): <literal>class</literal>에 대한 하나의 대안으로서,
|
|
연관된 클래스의 엔티티 이름.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="manytomany8">
|
|
<para>
|
|
<literal>property-ref</literal>: (옵션) 이 foreign 키에 조인된 연관 클래스의 프로퍼티의 이름.
|
|
지정되지 않을 경우, 연관 클래스의 프라이머리 키가 사용된다.
|
|
</para>
|
|
</callout>
|
|
</calloutlist>
|
|
</programlistingco>
|
|
|
|
<para>
|
|
몇몇 예제들, 먼저 문자열들을 가진 set:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<set name="names" table="person_names">
|
|
<key column="person_id"/>
|
|
<element column="person_name" type="string"/>
|
|
</set>]]></programlisting>
|
|
|
|
<para>
|
|
(<literal>order-by</literal> 속성에 의해 결정되는 반복 순서를 가진) 정수들을 포함하는 bag :
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<bag name="sizes"
|
|
table="item_sizes"
|
|
order-by="size asc">
|
|
<key column="item_id"/>
|
|
<element column="size" type="integer"/>
|
|
</bag>]]></programlisting>
|
|
|
|
<para>
|
|
엔티티들을 가진 배열 - 이 경우에, many to many 연관 :
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<array name="addresses"
|
|
table="PersonAddress"
|
|
cascade="persist">
|
|
<key column="personId"/>
|
|
<list-index column="sortOrder"/>
|
|
<many-to-many column="addressId" class="Address"/>
|
|
</array>]]></programlisting>
|
|
|
|
<para>
|
|
날짜들에 대한 문자열 인덱스들을 가진 map :
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<map name="holidays"
|
|
table="holidays"
|
|
schema="dbo"
|
|
order-by="hol_name asc">
|
|
<key column="id"/>
|
|
<map-key column="hol_name" type="string"/>
|
|
<element column="hol_date" type="date"/>
|
|
</map>]]></programlisting>
|
|
|
|
<para>
|
|
컴포넌트들의 리스트(다음 장에서 논의됨):
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<list name="carComponents"
|
|
table="CarComponents">
|
|
<key column="carId"/>
|
|
<list-index column="sortOrder"/>
|
|
<composite-element class="CarComponent">
|
|
<property name="price"/>
|
|
<property name="type"/>
|
|
<property name="serialNumber" column="serialNum"/>
|
|
</composite-element>
|
|
</list>]]></programlisting>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="collections-onetomany">
|
|
<title>One-to-many 연관들</title>
|
|
|
|
<para>
|
|
<emphasis>one to many 연관</emphasis>은 중재하는 콜렉션 테이블 없이 foreign 키를 통해 두 개의 클래스들의 테이블들을
|
|
연결시킨다. 이 매핑은 통상의 자바 콜렉션들의 어떤 의미를 상실한다:
|
|
</para>
|
|
|
|
<itemizedlist spacing="compact">
|
|
<listitem>
|
|
<para>
|
|
포함된 엔티티 클래스의 인스턴스는 그 콜렉션의 하나 이상의 인스턴스에 속하지 않을 수 있다
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
포함된 엔티티 클래스의 인스턴스는 콜렉션 인덱스의 하나 이상의 값에서 나타나지 않을 수 있다
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
<literal>Product</literal>로부터 <literal>Part</literal>로의 연관은 foreign 키 컬럼과 <literal>Part</literal>
|
|
테이블에 대한 인덱스 컬럼의 존재를 필요로 한다. <literal><one-to-many></literal> 태그는 이것이 one to many
|
|
연관임을 나타낸다.
|
|
</para>
|
|
|
|
<programlistingco>
|
|
<areaspec>
|
|
<area id="onetomany1" coords="2 60"/>
|
|
<area id="onetomany2" coords="3 60"/>
|
|
<area id="onetomany3" coords="4 60"/>
|
|
</areaspec>
|
|
<programlisting><![CDATA[<one-to-many
|
|
class="ClassName"
|
|
not-found="ignore|exception"
|
|
entity-name="EntityName"
|
|
node="element-name"
|
|
embed-xml="true|false"
|
|
/>]]></programlisting>
|
|
<calloutlist>
|
|
<callout arearefs="onetomany1">
|
|
<para>
|
|
<literal>class</literal> (필수): 연관된 클래스의 이름.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="onetomany2">
|
|
<para>
|
|
<literal>not-found</literal> (옵션 - 디폴트는 <literal>exception</literal>):
|
|
누락된 행들을 참조하는 캐시된 식별자들이 어떻게 처리될 것인지를 지정한다:
|
|
<literal>ignore</literal>는 누락된 한 행을 한 개의 연관으로 다룰 것이다.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="onetomany3">
|
|
<para>
|
|
<literal>entity-name</literal> (옵션): <literal>class</literal>에 대한 대안으로서,
|
|
연관된 클래스의 엔티티 이름.
|
|
</para>
|
|
</callout>
|
|
</calloutlist>
|
|
</programlistingco>
|
|
|
|
<para>
|
|
<literal><one-to-many></literal> 요소는 어떤 컬럼들을 선언하는데 필요하지 않음을 주목하라. 어딘가에
|
|
<literal>table</literal> 이름을 지정하는 것도 필수적이지 않다.
|
|
</para>
|
|
|
|
<para>
|
|
<emphasis>매우 중요한 노트</emphasis>: 만일 <literal><one-to-many></literal> 연관의 foreign 키 컬럼이
|
|
<literal>NOT NULL</literal>로 선언될 경우, 당신은 <literal><key></literal> 매핑을 <literal>not-null="true"</literal>로
|
|
선언해야 하거나 <literal>inverse="true"</literal>로 마크된 콜렉션 매핑을 가진 <emphasis>양방향 연관을 사용해야 한다</emphasis>.
|
|
양방향 연관들에 대한 논의는 이 장의 뒷부분을 보라.
|
|
</para>
|
|
|
|
<para>
|
|
이 예제는 name으로 <literal>Part</literal> 엔티티들을 가진 map을 보여준다(여기서 <literal>partName</literal>은
|
|
<literal>Part</literal>의 영속 프로퍼티이다). formula-기반 index의 사용을 주목하라.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<map name="parts"
|
|
cascade="all">
|
|
<key column="productId" not-null="true"/>
|
|
<map-key formula="partName"/>
|
|
<one-to-many class="Part"/>
|
|
</map>]]></programlisting>
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="collections-advancedmappings">
|
|
<title>개선된 콜렉션 매핑들</title>
|
|
|
|
<sect2 id="collections-sorted" revision="2">
|
|
<title>Sorted 콜렉션들</title>
|
|
|
|
<para>
|
|
Hibernate는 <literal>java.util.SortedMap</literal>과 <literal>java.util.SortedSet</literal>를 구현하는
|
|
콜렉션들을 지원한다. 당신은 매핑 파일 속에 하나의 comparator를 지정해야 한다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<set name="aliases"
|
|
table="person_aliases"
|
|
sort="natural">
|
|
<key column="person"/>
|
|
<element column="name" type="string"/>
|
|
</set>
|
|
|
|
<map name="holidays" sort="my.custom.HolidayComparator">
|
|
<key column="year_id"/>
|
|
<map-key column="hol_name" type="string"/>
|
|
<element column="hol_date" type="date"/>
|
|
</map>]]></programlisting>
|
|
|
|
<para>
|
|
<literal>sort</literal> 속성에 허용되는 값들은 <literal>unsorted</literal>, <literal>natural</literal>,
|
|
그리고 <literal>java.util.Comparator</literal>를 구현하는 클래스의 이름이다.
|
|
</para>
|
|
|
|
<para>
|
|
Sorted 콜렉션들은 <literal>java.util.TreeSet</literal> 또는 <literal>java.util.TreeMap</literal>처럼 행동한다.
|
|
</para>
|
|
|
|
<para>
|
|
만일 당신이 데이터베이스 그 자체가 콜렉션 요소들을 순서지우도록(order)원할 경우 <literal>set</literal>,
|
|
<literal>bag</literal> 또는<literal>map</literal> 매핑들에 대해 <literal>order-by</literal> 속성을 사용하라.
|
|
이 해결책은 JDK 1.4 이상의 버전에서만 이용 가능하다(그것은 <literal>LinkedHashSet</literal> 또는 <literal>LinkedHashMap</literal>을
|
|
사용하여 구현된다). 이것은 메모리 내가 아닌, SQL 질의 내에서 순서지움(ordering)을 수행한다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<set name="aliases" table="person_aliases" order-by="lower(name) asc">
|
|
<key column="person"/>
|
|
<element column="name" type="string"/>
|
|
</set>
|
|
|
|
<map name="holidays" order-by="hol_date, hol_name">
|
|
<key column="year_id"/>
|
|
<map-key column="hol_name" type="string"/>
|
|
<element column="hol_date type="date"/>
|
|
</map>]]></programlisting>
|
|
|
|
<para>
|
|
<literal>order-by</literal> 속성의 값은 HQL 순서지움(ordering)이 아니라 SQL 순서지움(ordering)임을 노트하라!
|
|
</para>
|
|
|
|
<para>
|
|
연관들은 콜렉션 <literal>filter()</literal>를 사용하여 실행 시에 어떤 임의의 criteria(기준)을 사용하여 정렬(sort)될
|
|
수도 있다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[sortedUsers = s.createFilter( group.getUsers(), "order by this.name" ).list();]]></programlisting>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="collections-bidirectional" revision="1">
|
|
<title>양방향 연관들</title>
|
|
|
|
<para>
|
|
<emphasis>양방향 연관</emphasis>은 연관의 양 "끝(end)들"로부터 네비게이션을 허용한다.
|
|
두 가지 종류의 양방향 연관들이 지원된다:
|
|
|
|
<variablelist>
|
|
<varlistentry>
|
|
<term>one-to-many</term>
|
|
<listitem>
|
|
<para>
|
|
한쪽 끝에 set 또는 bag 값을 갖고, 다른 쪽 긑에 단일 값을 가진 연관
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term>many-to-many</term>
|
|
<listitem>
|
|
<para>
|
|
양 끝에서 set 또는 bag 값을 가진 연관
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
</para>
|
|
|
|
<para>
|
|
당신은 동일한 두 개의 many-to-many 연관들을 동일한 데이터베이스 테이블로 간단하게 매핑하고 한 쪽 끝을
|
|
<emphasis>inverse</emphasis>(당신의 선택은 하나이지만, 그것은 인덱싱된 콜렉션일 수 없다)로 선언함으로써 하나의 양방향
|
|
many-to-many 연관을 지정할 수도 있다.
|
|
</para>
|
|
|
|
<para>
|
|
다음은 양방향 many-to-many 연관에 관한 예제이다; 각각의 카테고리는 많은 아이템들을 가질 수 있고 각각의 아이템은 많은
|
|
카테고리들 속에 있을 수 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<class name="Category">
|
|
<id name="id" column="CATEGORY_ID"/>
|
|
...
|
|
<bag name="items" table="CATEGORY_ITEM">
|
|
<key column="CATEGORY_ID"/>
|
|
<many-to-many class="Item" column="ITEM_ID"/>
|
|
</bag>
|
|
</class>
|
|
|
|
<class name="Item">
|
|
<id name="id" column="CATEGORY_ID"/>
|
|
...
|
|
|
|
<!-- inverse end -->
|
|
<bag name="categories" table="CATEGORY_ITEM" inverse="true">
|
|
<key column="ITEM_ID"/>
|
|
<many-to-many class="Category" column="CATEGORY_ID"/>
|
|
</bag>
|
|
</class>]]></programlisting>
|
|
|
|
<para>
|
|
연관의 inverse 끝(end)에 대해서만 행해진 변경들은 영속화 되지 <emphasis>않는다</emphasis>. 이것은 Hibernate가
|
|
모든 양방향 연관에 대해 메모리 내에 두 개의 표상들을 갖는다는 점을 의미한다: A로부터 B로의 하나의 링크와 B로부터 A로의 또 다른 링크.
|
|
만일 당신이 자바 객체 모형에 대해 그리고 자바에서 many-to-many 관계를 생성시키는 방법에 대해 생각하면 이것은 이해하기가 더 쉽다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[
|
|
category.getItems().add(item); // The category now "knows" about the relationship
|
|
item.getCategories().add(category); // The item now "knows" about the relationship
|
|
|
|
session.persist(item); // The relationship won't be saved!
|
|
session.persist(category); // The relationship will be saved]]></programlisting>
|
|
|
|
<para>
|
|
non-inverse 측은 메모리 내 표상을 데이터베이스로 저장하는데 사용된다.
|
|
</para>
|
|
|
|
<para>
|
|
당신은 하나의 one-to-many 연관을 하나의 many-to-one 연관으로서 동일한 테이블 컬럼(들)로 매핑하고 many-값을 가진 끝(end)을
|
|
<literal>inverse="true"</literal>로 선언함으로써 하나의 양방향 연관을 정의할 수도 있다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<class name="Parent">
|
|
<id name="id" column="parent_id"/>
|
|
....
|
|
<set name="children" inverse="true">
|
|
<key column="parent_id"/>
|
|
<one-to-many class="Child"/>
|
|
</set>
|
|
</class>
|
|
|
|
<class name="Child">
|
|
<id name="id" column="child_id"/>
|
|
....
|
|
<many-to-one name="parent"
|
|
class="Parent"
|
|
column="parent_id"
|
|
not-null="true"/>
|
|
</class>]]></programlisting>
|
|
|
|
<para>
|
|
연관의 한쪽 끝을 <literal>inverse="true"</literal>로 매핑하는 것은 cascade들을 가진 오퍼레이션에 영향을 주지 않으며,
|
|
이것들은 orthogonal(직교) 개념들이다!
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="collections-indexedbidirectional">
|
|
<title>인덱싱된 콜렉션들을 가진 양방향 연관들</title>
|
|
<para>
|
|
한쪽 끝이 하나의 <literal><list></literal> 또는 <literal><map></literal>으로서 표현되는 양방향
|
|
연관은 특별한 검토를 필요로 한다. 만일 인덱스 컬럼으로 매핑되는 child 클래스의 프로퍼티가 하나 존재한다면 문제가 없고,
|
|
우리는 콜렉션 매핑 상에 <literal>inverse="true"</literal>를 사용하여 계속할 수 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<class name="Parent">
|
|
<id name="id" column="parent_id"/>
|
|
....
|
|
<map name="children" inverse="true">
|
|
<key column="parent_id"/>
|
|
<map-key column="name"
|
|
type="string"/>
|
|
<one-to-many class="Child"/>
|
|
</map>
|
|
</class>
|
|
|
|
<class name="Child">
|
|
<id name="id" column="child_id"/>
|
|
....
|
|
<property name="name"
|
|
not-null="true"/>
|
|
<many-to-one name="parent"
|
|
class="Parent"
|
|
column="parent_id"
|
|
not-null="true"/>
|
|
</class>]]></programlisting>
|
|
|
|
<para>
|
|
그러나 만일 child 클래스 상에 그런 프로퍼티가 존재하지 않을 경우, 우리는 그 연관을 진정하게 양방향으로 간주할 수 없다
|
|
(다른 쪽 끝에서 이용가능하지 않은 그 연관의 끝에서 이용 가능한 정보가 존재한다). 이 경우에 우리는 그 콜렉션을
|
|
<literal>inverse="true"</literal>로 매핑시킬 수 없다. 대신에 우리는 다음 매핑을 사용할 수 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<class name="Parent">
|
|
<id name="id" column="parent_id"/>
|
|
....
|
|
<map name="children">
|
|
<key column="parent_id"
|
|
not-null="true"/>
|
|
<map-key column="name"
|
|
type="string"/>
|
|
<one-to-many class="Child"/>
|
|
</map>
|
|
</class>
|
|
|
|
<class name="Child">
|
|
<id name="id" column="child_id"/>
|
|
....
|
|
<many-to-one name="parent"
|
|
class="Parent"
|
|
column="parent_id"
|
|
insert="false"
|
|
update="false"
|
|
not-null="true"/>
|
|
</class>]]></programlisting>
|
|
|
|
<para>
|
|
이 매핑에서 그 연관의 콜렉션 값을 가진 끝이 foreign 키에 대한 업데이트 책임이 있음을 노트하라.
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="collections-ternary">
|
|
<title>Ternary associations(세겹 연관들)</title>
|
|
|
|
<para>
|
|
세 겹의 연관을 매핑하는 세 가지 가능한 접근법들이 존재한다. 하나의 접근법은 그것의 인덱스로서 연관관계를 가진
|
|
<literal>Map</literal>을 사용하는 것이다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<map name="contracts">
|
|
<key column="employer_id" not-null="true"/>
|
|
<map-key-many-to-many column="employee_id" class="Employee"/>
|
|
<one-to-many class="Contract"/>
|
|
</map>]]></programlisting>
|
|
|
|
<programlisting><![CDATA[<map name="connections">
|
|
<key column="incoming_node_id"/>
|
|
<map-key-many-to-many column="outgoing_node_id" class="Node"/>
|
|
<many-to-many column="connection_id" class="Connection"/>
|
|
</map>]]></programlisting>
|
|
|
|
<para>
|
|
두 번째 접근법은 그 연관을 엔티티 클래스로서 단순하게 리모델링 하는 것이다. 이것은 우리가 가장 공통적으로 사용하는 접근법이다.
|
|
</para>
|
|
|
|
<para>
|
|
마지막 대안은 우리가 나중에 논의하게 될 composite 요소들을 사용하는 것이다.
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="collections-idbag" revision="1">
|
|
<title><literal><idbag></literal> 사용하기</title>
|
|
|
|
<para>
|
|
만일 당신이 composite 키들이 나쁜 것이고 엔티티들이 합성 식별자들(대용 키들, surrogate keys)을 가져야 한다는
|
|
우리의 견해를 전적으로 수용할 경우, 당신은 우리가 지금까지 보여주었던 값들을 가진 콜렉션들과 many to many 연관들이 모두
|
|
composite 키들을 가진 테이블들로 매핑된다는 약간 이상한 점을 발견할 수도 있다! 이제 이 점은 꽤 논의의 여지가 있다; 순수한
|
|
연관 테이블은 (비록 composite 값들을 가진 콜렉션<emphasis>일 수도</emphasis> 있을지라도) 대용 키로부터 많은 이점을
|
|
취하지 않는 것처럼 보인다. 그럼에도 불구하고 Hibernate는 당신이 값들을 가진 콜렉션들과 many to many 연관들을 대용 키를 가진
|
|
테이블로 매핑시키는 것을 당신에게 허용해주는 특징을 제공한다.
|
|
</para>
|
|
|
|
<para>
|
|
<literal><idbag></literal> 요소는 bag 의미를 가진 <literal>List</literal>(또는 <literal>Collection</literal>)을
|
|
매핑하도록 당신에게 허용해준다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<idbag name="lovers" table="LOVERS">
|
|
<collection-id column="ID" type="long">
|
|
<generator class="sequence"/>
|
|
</collection-id>
|
|
<key column="PERSON1"/>
|
|
<many-to-many column="PERSON2" class="Person" fetch="join"/>
|
|
</idbag>]]></programlisting>
|
|
|
|
<para>
|
|
당신이 볼 수 있듯이, <literal><idbag></literal>은 마치 엔티티 클래스인양 synthetic id generator(합성 id 생성기)를
|
|
갖는다! 다른 대용 키는 각각의 콜렉션 행에 할당된다. 하지만 Hibernate는 특정 행의 대용 키 값을 발견하는 메커니즘을 제공하지 않는다.
|
|
</para>
|
|
|
|
<para>
|
|
<literal><idbag></literal>의 업데이트 퍼포먼스는 정규 <literal><bag></literal> 보다 훨씬 좋다는 점을
|
|
노트하라! Hibernate는 마치 list, map, 또는 set인양, 개별 행들을 효율적으로 위치지울 수 있고 그것들을 개별적으로 업데이트
|
|
하거나 삭제시킬 수 있다.
|
|
</para>
|
|
|
|
<para>
|
|
현재 구현에서, <literal>native</literal> 식별자 생성 방도는 <literal><idbag></literal> 콜렉션 식별자들에 대해
|
|
지원되지 않는다.
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
<!--다음 요소를 문서화하지 않음 -->
|
|
|
|
<!--sect1 id="collections-heterogeneous">
|
|
<title>Heterogeneous Associations</title>
|
|
|
|
<para>
|
|
<literal><many-to-any></literal>와 <literal><index-many-to-any></literal> 요소들은
|
|
진정한 이종의(heterogeneous) 연관들을 제공한다. 이들 매핑 요소들은 <literal><any></literal> 요소와
|
|
동일한 방법으로 동작한다 - 그리고 또한 아마 드물게 사용될 수 있을 것이다.
|
|
</para>
|
|
|
|
</sect1-->
|
|
|
|
<sect1 id="collections-example" revision="1">
|
|
<title>콜렉션 예제들</title>
|
|
|
|
<para>
|
|
앞의 절들은 꽤 혼동스럽다. 따라서 예제를 살펴보자. 다음 클래스:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[package eg;
|
|
import java.util.Set;
|
|
|
|
public class Parent {
|
|
private long id;
|
|
private Set children;
|
|
|
|
public long getId() { return id; }
|
|
private void setId(long id) { this.id=id; }
|
|
|
|
private Set getChildren() { return children; }
|
|
private void setChildren(Set children) { this.children=children; }
|
|
|
|
....
|
|
....
|
|
}]]></programlisting>
|
|
|
|
<para>
|
|
는 <literal>Child</literal> 인스턴스들을 가진 하나의 콜렉션을 갖고 있다. 만일 각각의 자식이 최소한 한 개의 부모를 가질 경우,
|
|
대부분의 고유한 매핑은 one-to-many 연관이다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<hibernate-mapping>
|
|
|
|
<class name="Parent">
|
|
<id name="id">
|
|
<generator class="sequence"/>
|
|
</id>
|
|
<set name="children">
|
|
<key column="parent_id"/>
|
|
<one-to-many class="Child"/>
|
|
</set>
|
|
</class>
|
|
|
|
<class name="Child">
|
|
<id name="id">
|
|
<generator class="sequence"/>
|
|
</id>
|
|
<property name="name"/>
|
|
</class>
|
|
|
|
</hibernate-mapping>]]></programlisting>
|
|
|
|
<para>
|
|
이것은 다음 테이블 정의들로 매핑된다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[create table parent ( id bigint not null primary key )
|
|
create table child ( id bigint not null primary key, name varchar(255), parent_id bigint )
|
|
alter table child add constraint childfk0 (parent_id) references parent]]></programlisting>
|
|
|
|
<para>
|
|
만일 부모가 <emphasis>필수적</emphasis>이라면, 양방향 one-to-many 연관관계를 사용하라:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<hibernate-mapping>
|
|
|
|
<class name="Parent">
|
|
<id name="id">
|
|
<generator class="sequence"/>
|
|
</id>
|
|
<set name="children" inverse="true">
|
|
<key column="parent_id"/>
|
|
<one-to-many class="Child"/>
|
|
</set>
|
|
</class>
|
|
|
|
<class name="Child">
|
|
<id name="id">
|
|
<generator class="sequence"/>
|
|
</id>
|
|
<property name="name"/>
|
|
<many-to-one name="parent" class="Parent" column="parent_id" not-null="true"/>
|
|
</class>
|
|
|
|
</hibernate-mapping>]]></programlisting>
|
|
|
|
<para>
|
|
<literal>NOT NULL</literal> 컨스트레인트를 주목하라:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[create table parent ( id bigint not null primary key )
|
|
create table child ( id bigint not null
|
|
primary key,
|
|
name varchar(255),
|
|
parent_id bigint not null )
|
|
alter table child add constraint childfk0 (parent_id) references parent]]></programlisting>
|
|
|
|
<para>
|
|
대안적으로, 만일 당신이 이 연관관계가 단방향이어야 함을 절대적으로 역설할 경우, 당신은 <literal><key></literal>
|
|
매핑 상에 <literal>NOT NULL</literal> 컨스트레인트를 선언할 수 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<hibernate-mapping>
|
|
|
|
<class name="Parent">
|
|
<id name="id">
|
|
<generator class="sequence"/>
|
|
</id>
|
|
<set name="children">
|
|
<key column="parent_id" not-null="true"/>
|
|
<one-to-many class="Child"/>
|
|
</set>
|
|
</class>
|
|
|
|
<class name="Child">
|
|
<id name="id">
|
|
<generator class="sequence"/>
|
|
</id>
|
|
<property name="name"/>
|
|
</class>
|
|
|
|
</hibernate-mapping>]]></programlisting>
|
|
|
|
<para>
|
|
반면에, 만일 자식이 여러 부모들을 가질 수 있을 경우, many-to-many 연관이 적절하다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<hibernate-mapping>
|
|
|
|
<class name="Parent">
|
|
<id name="id">
|
|
<generator class="sequence"/>
|
|
</id>
|
|
<set name="children" table="childset">
|
|
<key column="parent_id"/>
|
|
<many-to-many class="Child" column="child_id"/>
|
|
</set>
|
|
</class>
|
|
|
|
<class name="Child">
|
|
<id name="id">
|
|
<generator class="sequence"/>
|
|
</id>
|
|
<property name="name"/>
|
|
</class>
|
|
|
|
</hibernate-mapping>]]></programlisting>
|
|
|
|
<para>
|
|
테이블 정의들:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[create table parent ( id bigint not null primary key )
|
|
create table child ( id bigint not null primary key, name varchar(255) )
|
|
create table childset ( parent_id bigint not null,
|
|
child_id bigint not null,
|
|
primary key ( parent_id, child_id ) )
|
|
alter table childset add constraint childsetfk0 (parent_id) references parent
|
|
alter table childset add constraint childsetfk1 (child_id) references child]]></programlisting>
|
|
|
|
<para>
|
|
부모/자식 관계 매핑을 연습하는 더 많은 예제들과 전체 리허설은 <xref linkend="example-parentchild"/>를 보라.
|
|
</para>
|
|
|
|
<para>
|
|
비록 더 많은 신종 연관 매핑들이 가능할지라도, 우리는 다음 장에서 모든 가능성들을 분류할 것이다.
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
</chapter>
|