hibernate-orm/doc/reference/ko/modules/association_mapping.xml
2007-06-29 19:55:14 +00:00

604 lines
21 KiB
XML

<chapter id="associations">
<title>연관 매핑들</title>
<sect1 id="assoc-intro" revision="1">
<title>개요</title>
<para>
연관 매핑들은 올바른 것을 얻기가 종종 가장 어려운 것이다. 이 절에서 우리는 단방향 매핑들에서 시작하고, 그런 다음 양방향 경우들을
검토함으로써, 하나씩 표준적인 경우들을 상세히 논의할 것이다. 우리는 모든 예제들에서 <literal>Person</literal>
<literal>Address</literal>를 사용할 것이다.
</para>
<para>
우리는 연관들을 중재하는 join 테이블로 매핑시킬 것인지 여부에 따라, 그리고 multiplicity(다중성)에 따라 연관들을 분류할 것이다.
</para>
<para>
null 허용 가능한 foreign 키들은 전통적인 데이터 모델링에서 좋은 실례로 간주되지 않아서, 모든 우리의 예제들은 not null
foreign 키들을 사용한다. 이것은 Hibernate에서 필수가 아니고, 당신이 null 허용 가능 컨스트레인트들을 드롭시킬 경우 매핑들은
모두 동작할 것이다.
</para>
</sect1>
<sect1 id="assoc-unidirectional" revision="1">
<title>단방향 연관들</title>
<sect2 id="assoc-unidirectional-m21">
<title>many to one</title>
<para>
<emphasis>단방향 many-to-one 연관</emphasis>은 가장 공통적인 종류의 단방향 연관이다.
</para>
<programlisting><![CDATA[<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<many-to-one name="address"
column="addressId"
not-null="true"/>
</class>
<class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
</class>]]></programlisting>
<programlisting><![CDATA[
create table Person ( personId bigint not null primary key, addressId bigint not null )
create table Address ( addressId bigint not null primary key )
]]></programlisting>
</sect2>
<sect2 id="assoc-unidirectional-121">
<title>one to one</title>
<para>
<emphasis>foreign 키에 대한 단방향 one-to-one 연관은 대개 아주 동일하다.</emphasis> 유일한 차이점은
컬럼 유일(unique) 컨스트레인트이다.
</para>
<programlisting><![CDATA[<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<many-to-one name="address"
column="addressId"
unique="true"
not-null="true"/>
</class>
<class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
</class>]]></programlisting>
<programlisting><![CDATA[
create table Person ( personId bigint not null primary key, addressId bigint not null unique )
create table Address ( addressId bigint not null primary key )
]]></programlisting>
<para>
<emphasis>하나의 프라이머리 키에 대한 단방향 one-to-one 연관</emphasis>은 대개 특별한 id 생성기를 사용한다.
(이 예제에서 연관의 방향이 역전되었음을 주목하라.)
</para>
<programlisting><![CDATA[<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
</class>
<class name="Address">
<id name="id" column="personId">
<generator class="foreign">
<param name="property">person</param>
</generator>
</id>
<one-to-one name="person" constrained="true"/>
</class>]]></programlisting>
<programlisting><![CDATA[
create table Person ( personId bigint not null primary key )
create table Address ( personId bigint not null primary key )
]]></programlisting>
</sect2>
<sect2 id="assoc-unidirectional-12m">
<title>one to many</title>
<para>
<emphasis>하나의 foreign 키에 대한 단방향 one-to-many 연관</emphasis>은 매우 색다른 경우이고, 실제로 권장되지 않는다.
</para>
<programlisting><![CDATA[<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<set name="addresses">
<key column="personId"
not-null="true"/>
<one-to-many class="Address"/>
</set>
</class>
<class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
</class>]]></programlisting>
<programlisting><![CDATA[
create table Person ( personId bigint not null primary key )
create table Address ( addressId bigint not null primary key, personId bigint not null )
]]></programlisting>
<para>
우리는 이런 종류의 연관에 대해 하나의 join 테이블을 사용하는 것이 더 좋다고 생각한다.
</para>
</sect2>
</sect1>
<sect1 id="assoc-unidirectional-join" revision="1">
<title>join 테이블들에 대한 단방향 연관들</title>
<sect2 id="assoc-unidirectional-join-12m">
<title>one to many</title>
<para>
<emphasis>하나의 join 테이블에 대한 단방향 one-to-many 연관</emphasis>이 보다 더 선호된다. <literal>unique="true"</literal>
지정함으로써 우리는 many-to-many에서 one-to-many로 아중성(multiplicity)를 변경시켰음을 주목하라.
</para>
<programlisting><![CDATA[<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<set name="addresses" table="PersonAddress">
<key column="personId"/>
<many-to-many column="addressId"
unique="true"
class="Address"/>
</set>
</class>
<class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
</class>]]></programlisting>
<programlisting><![CDATA[
create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId not null, addressId bigint not null primary key )
create table Address ( addressId bigint not null primary key )
]]></programlisting>
</sect2>
<sect2 id="assoc-unidirectional-join-m21">
<title>many to one</title>
<para>
<emphasis>하나의 join 테이블에 대한 단방향 many-to-one 연관</emphasis>은 그 연관이 선택적일 때 매우 공통적이다.
</para>
<programlisting><![CDATA[<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<join table="PersonAddress"
optional="true">
<key column="personId" unique="true"/>
<many-to-one name="address"
column="addressId"
not-null="true"/>
</join>
</class>
<class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
</class>]]></programlisting>
<programlisting><![CDATA[
create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId bigint not null primary key, addressId bigint not null )
create table Address ( addressId bigint not null primary key )
]]></programlisting>
</sect2>
<sect2 id="assoc-unidirectional-join-121">
<title>one to one</title>
<para>
<emphasis>하나의 join 테이블에 대한 단방향 one-to-one 연관</emphasis>은 극히 통상적이지 않지만 가능하다.
</para>
<programlisting><![CDATA[<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<join table="PersonAddress"
optional="true">
<key column="personId"
unique="true"/>
<many-to-one name="address"
column="addressId"
not-null="true"
unique="true"/>
</join>
</class>
<class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
</class>]]></programlisting>
<programlisting><![CDATA[
create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
create table Address ( addressId bigint not null primary key )
]]></programlisting>
</sect2>
<sect2 id="assoc-unidirectional-join-m2m">
<title>many to many</title>
<para>
마지막으로, 우리는 <emphasis>단방향 many-to-many 연관</emphasis>을 갖는다.
</para>
<programlisting><![CDATA[<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<set name="addresses" table="PersonAddress">
<key column="personId"/>
<many-to-many column="addressId"
class="Address"/>
</set>
</class>
<class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
</class>]]></programlisting>
<programlisting><![CDATA[
create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
create table Address ( addressId bigint not null primary key )
]]></programlisting>
</sect2>
</sect1>
<sect1 id="assoc-bidirectional" revision="1">
<title>양방향 연관들</title>
<sect2 id="assoc-bidirectional-m21" revision="2">
<title>one to many / many to one</title>
<para>
<emphasis>양방향 many-to-one 연관</emphasis>은 가장 공통된 종류의 연관이다.(이것은 표준 부모/자식 관계이다. )
</para>
<programlisting><![CDATA[<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<many-to-one name="address"
column="addressId"
not-null="true"/>
</class>
<class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
<set name="people" inverse="true">
<key column="addressId"/>
<one-to-many class="Person"/>
</set>
</class>]]></programlisting>
<programlisting><![CDATA[
create table Person ( personId bigint not null primary key, addressId bigint not null )
create table Address ( addressId bigint not null primary key )
]]></programlisting>
<para>
만일 당신이 <literal>List</literal>(또는 다른 인덱싱 된 콜렉션)을 사용할 경우 당신은 foreign key의
<literal>key</literal> 컬럼을 <literal>not null</literal>로 설정하고, Hibernate로 하여금
각각의 요소의 인덱스를 유지관리하기 위해 (<literal>update="false"</literal>
<literal>insert="false"</literal>를 설정함으로써 다른 측을 가상적으로 inverse로 만들어)
그 콜렉션들 측으로부터 연관을 관리하도록 할 필요가 있다:
</para>
<programlisting><![CDATA[<class name="Person">
<id name="id"/>
...
<many-to-one name="address"
column="addressId"
not-null="true"
insert="false"
update="false"/>
</class>
<class name="Address">
<id name="id"/>
...
<list name="people">
<key column="addressId" not-null="true"/>
<list-index column="peopleIdx"/>
<one-to-many class="Person"/>
</list>
</class>]]></programlisting>
<para>
만일 기본 외래 키 컬럼이 <literal>NOT NULL</literal>일 경우 콜렉션 매핑의 <literal>&lt;key&gt;</literal>
요소 상에 <literal>not-null="true"</literal>를 정의하는 것이 중요하다. 내포된
<literal>&lt;column&gt;</literal> 요소 상에 <literal>not-null="true"</literal>
선언하지 말고, <literal>&lt;key&gt;</literal> 요소 상에 선언하라.
</para>
</sect2>
<sect2 id="assoc-bidirectional-121">
<title>one to one</title>
<para>
<emphasis>foreign에 대한 양방향 one-to-one 연관</emphasis>은 꽤 공통적이다.
</para>
<programlisting><![CDATA[<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<many-to-one name="address"
column="addressId"
unique="true"
not-null="true"/>
</class>
<class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
<one-to-one name="person"
property-ref="address"/>
</class>]]></programlisting>
<programlisting><![CDATA[
create table Person ( personId bigint not null primary key, addressId bigint not null unique )
create table Address ( addressId bigint not null primary key )
]]></programlisting>
<para>
<emphasis>하나의 프라이머리 키에 대한 양방향 one-to-one 연관</emphasis>은 특별한 id 생성기를 사용한다.
</para>
<programlisting><![CDATA[<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<one-to-one name="address"/>
</class>
<class name="Address">
<id name="id" column="personId">
<generator class="foreign">
<param name="property">person</param>
</generator>
</id>
<one-to-one name="person"
constrained="true"/>
</class>]]></programlisting>
<programlisting><![CDATA[
create table Person ( personId bigint not null primary key )
create table Address ( personId bigint not null primary key )
]]></programlisting>
</sect2>
</sect1>
<sect1 id="assoc-bidirectional-join" revision="1">
<title>join 테이블들에 대한 양방향 연관들</title>
<sect2 id="assoc-bidirectional-join-12m">
<title>one to many / many to one</title>
<para>
<emphasis>하나의 join 테이블에 대한 양방향 one-to-many 연관</emphasis>. <literal>inverse="true"</literal>
연관의 어느 쪽 끝이든 콜렉션 측으로 또는 join 측으로 갈 수 있다.
</para>
<programlisting><![CDATA[<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<set name="addresses"
table="PersonAddress">
<key column="personId"/>
<many-to-many column="addressId"
unique="true"
class="Address"/>
</set>
</class>
<class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
<join table="PersonAddress"
inverse="true"
optional="true">
<key column="addressId"/>
<many-to-one name="person"
column="personId"
not-null="true"/>
</join>
</class>]]></programlisting>
<programlisting><![CDATA[
create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId bigint not null, addressId bigint not null primary key )
create table Address ( addressId bigint not null primary key )
]]></programlisting>
</sect2>
<sect2 id="assoc-bidirectional-join-121">
<title>one to one</title>
<para>
<emphasis>하나의 join 테이블에 대한 양방향 one-to-one 연관</emphasis>은 극히 통상적이지 않지만, 가능하다.
</para>
<programlisting><![CDATA[<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<join table="PersonAddress"
optional="true">
<key column="personId"
unique="true"/>
<many-to-one name="address"
column="addressId"
not-null="true"
unique="true"/>
</join>
</class>
<class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
<join table="PersonAddress"
optional="true"
inverse="true">
<key column="addressId"
unique="true"/>
<many-to-one name="person"
column="personId"
not-null="true"
unique="true"/>
</join>
</class>]]></programlisting>
<programlisting><![CDATA[
create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
create table Address ( addressId bigint not null primary key )
]]></programlisting>
</sect2>
<sect2 id="assoc-bidirectional-join-m2m" revision="1">
<title>many to many</title>
<para>
마지막으로, 우리는 하나의 <emphasis>양방향 many-to-many 연관</emphasis>을 갖는다.
</para>
<programlisting><![CDATA[<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<set name="addresses" table="PersonAddress">
<key column="personId"/>
<many-to-many column="addressId"
class="Address"/>
</set>
</class>
<class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
<set name="people" inverse="true" table="PersonAddress">
<key column="addressId"/>
<many-to-many column="personId"
class="Person"/>
</set>
</class>]]></programlisting>
<programlisting><![CDATA[
create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
create table Address ( addressId bigint not null primary key )
]]></programlisting>
</sect2>
</sect1>
<sect1 id="assoc-complex">
<title>보다 복잡한 연관 매핑들</title>
<para>
보다 복잡한 연관 조인들은 <emphasis>극기</emphasis> 드물다.
Hibernate는 매핑 문서들 내에 삽입된 SQL 조각들을 사용하여 보다 복잡한 상황을 처리하는 것을
가능하도록 해준다. 예를 들어, 만일 계좌 내역 정보 데이터를 가진 하나이 테이블이
<literal>accountNumber</literal>, <literal>effectiveEndDate</literal>
그리고 <literal>effectiveStartDate</literal> 컬럼들을 정의할 경우, 다음과 같이 매핑된다:
</para>
<programlisting><![CDATA[<properties name="currentAccountKey">
<property name="accountNumber" type="string" not-null="true"/>
<property name="currentAccount" type="boolean">
<formula>case when effectiveEndDate is null then 1 else 0 end</formula>
</property>
</properties>
<property name="effectiveEndDate" type="date"/>
<property name="effectiveStateDate" type="date" not-null="true"/>]]></programlisting>
<para>
그때 우리는 다음을 사용하여 하나의 연관을 <emphasis>현재</emphasis> 인스턴스
(null <literal>effectiveEndDate</literal>을 가진 인스턴스)로 매핑시킬 수 있다:
</para>
<programlisting><![CDATA[<many-to-one name="currentAccountInfo"
property-ref="currentAccountKey"
class="AccountInfo">
<column name="accountNumber"/>
<formula>'1'</formula>
</many-to-one>]]></programlisting>
<para>
보다 복잡한 예제에서, <literal>Employee</literal><literal>Organization</literal> 사이의
연관이 전체 고용 내역 데이터를 가진 <literal>Employment</literal> 테이블 내에 유지된다고 가정하자.
그때 종업원의 <emphasis>가장 최근의</emphasis> 고용주에 대한 하나의 연관(가장 최근의
<literal>startDate</literal>를 갖고 있는 것)이 다음 방법으로 매핑될 수 있다:
</para>
<programlisting><![CDATA[<join>
<key column="employeeId"/>
<subselect>
select employeeId, orgId
from Employments
group by orgId
having startDate = max(startDate)
</subselect>
<many-to-one name="mostRecentEmployer"
class="Organization"
column="orgId"/>
</join>]]></programlisting>
<para>
당신은 이 기능으로 아주 생산성을 얻을 수 있지만, 그것은 대개 HQL 또는 criteria 질의를 사용하여 이들 종류의 경우들을
처리하는 것이 보다 실용적이다.
</para>
</sect1>
</chapter>