hibernate-orm/reference/ko/modules/component_mapping.xml
Gavin King fc38fb17c4 fixed HHH-1078
git-svn-id: https://svn.jboss.org/repos/hibernate/trunk/Hibernate3/doc@8466 1b8cb986-b30d-0410-93ca-fae66ebed9b2
2005-10-26 20:30:59 +00:00

375 lines
17 KiB
XML

<chapter id="components">
<title>Component 매핑</title>
<para>
<emphasis>component</emphasis>의 개념은 Hibernate에서 다른 용도로 몇몇 다른 컨텍스트들 내에서 재사용된다.
</para>
<sect1 id="components-dependentobjects" revision="2" >
<title>종속 객체들</title>
<para>
하나의 컴포넌트는 엔티티 참조가 아닌, value 타입으로서 영속화 되는 하나의 포함된 객체이다. "컴포넌트" 용어는
(아키텍처 수준의 컴포넌트들이 아닌) composition(구성,합성)에 대한 객체-지향적인 개념을 언급한다.
예를 들어 당신은 다음과 같이 개인을 모형화 시킬 수도 있다:
</para>
<programlisting><![CDATA[public class Person {
private java.util.Date birthday;
private Name name;
private String key;
public String getKey() {
return key;
}
private void setKey(String key) {
this.key=key;
}
public java.util.Date getBirthday() {
return birthday;
}
public void setBirthday(java.util.Date birthday) {
this.birthday = birthday;
}
public Name getName() {
return name;
}
public void setName(Name name) {
this.name = name;
}
......
......
}]]></programlisting>
<programlisting><![CDATA[public class Name {
char initial;
String first;
String last;
public String getFirst() {
return first;
}
void setFirst(String first) {
this.first = first;
}
public String getLast() {
return last;
}
void setLast(String last) {
this.last = last;
}
public char getInitial() {
return initial;
}
void setInitial(char initial) {
this.initial = initial;
}
}]]></programlisting>
<para>
이제 <literal>Name</literal><literal>Person</literal>의 컴포넌트로서 영속화 될 수도 있다. <literal>Name</literal>
그것의 영속 프로퍼티들에 대한 getter 메소드와 setter 메소드를 정의하지만, 어떤 인터페이스들이나 식별자 프로퍼티들을 선언하는 것을
필요로 하지 않음을 주목하라.
</para>
<para>
우리의 Hibernate 매핑은 다음과 같을 것이다:
</para>
<programlisting><![CDATA[<class name="eg.Person" table="person">
<id name="Key" column="pid" type="string">
<generator class="uuid"/>
</id>
<property name="birthday" type="date"/>
<component name="Name" class="eg.Name"> <!-- class attribute optional -->
<property name="initial"/>
<property name="first"/>
<property name="last"/>
</component>
</class>]]></programlisting>
<para>
person 테이블은
<literal>pid</literal>,
<literal>birthday</literal>,
<literal>initial</literal>,
<literal>first</literal>,
<literal>last</literal> 컬럼들을 가질 것이다.
</para>
<para>
모든 값(value) 타입들처럼, 컴포넌트들은 공유된 참조들을 지원하지 않는다. 달리 말해, 두 명의 개인들은 동일한 이름을 가질 수
있지만, 두 개의 person 객체들은 오직 값 만이 "동일한" 두 개의 독립적인 name 객체들을 포함할 것이다. 컴포넌트의 null 값 의미는
<emphasis>특별한 용도를 위한 것이다</emphasis>. 포함된 객체를 다시 로드시킬 때, Hibernate는 모든 컴포넌트 컬럼들이
null일 경우에 전체 컴포넌트가 null이라고 가정할 것이다. 이것은 대부분의 용도에 맞을 것이다.
</para>
<para>
컴포넌트의 프로퍼티들은 임의의 Hibernate 타입일 수 있다(콜렉션들, many-to-one 연관들, 다른 컴포넌트들, 기타).
내포된 컴포넌트들은 신종의 사용례로 간주되지 <emphasis>않을</emphasis> 것이다. Hibernate는 매우 잘 정제된 객체 모형을
지원하도록 고안되어있다.
</para>
<para>
<literal>&lt;component&gt;</literal> 요소는 컴포넌트 클래스의 프로퍼티를 포함되는 엔티티에 대한 역 참조로서 매핑시키는
<literal>&lt;parent&gt;</literal> 서브요소를 허용한다.
</para>
<programlisting><![CDATA[<class name="eg.Person" table="person">
<id name="Key" column="pid" type="string">
<generator class="uuid"/>
</id>
<property name="birthday" type="date"/>
<component name="Name" class="eg.Name" unique="true">
<parent name="namedPerson"/> <!-- reference back to the Person -->
<property name="initial"/>
<property name="first"/>
<property name="last"/>
</component>
</class>]]></programlisting>
</sect1>
<sect1 id="components-incollections" revision="1">
<title>종속 객체들을 가진 콜렉션들</title>
<para>
컴포넌트들을 가진 콜렉션들이 지원된다(예를 들면 <literal>Name</literal> 타입을 가진 배열).
<literal>&lt;element&gt;</literal> 태그를 <literal>&lt;composite-element&gt;</literal> 태그로
대체시켜서 당신의 컴포넌트 콜렉션을 선언하라.
</para>
<programlisting><![CDATA[<set name="someNames" table="some_names" lazy="true">
<key column="id"/>
<composite-element class="eg.Name"> <!-- class attribute required -->
<property name="initial"/>
<property name="first"/>
<property name="last"/>
</composite-element>
</set>]]></programlisting>
<para>
노트: 만일 당신이 composite 요소를 가진 하나의 <literal>Set</literal>를 정의할 경우, <literal>equals()</literal>
<literal>hashCode()</literal>를 정확하게 구현하는 것이 매우 중요하다.
</para>
<para>
Composite 요소들은 컴포넌트들을 포함하지만 콜렉션들을 포함하지 않는다. 만일 당신의 composite 요소 자체가 컴포넌트들을 포함할
경우, <literal>&lt;nested-composite-element&gt;</literal> 태그를 사용하라. 이것은 꽤 신종의 경우-그것들 자체가
컴포넌트들을 갖고 있는 컴포넌트들의 콜렉션-이다. 이 단계에서 당신은 one-to-many 연관이 더 적절한지를 당신 스스로에게 질문하게
될 것이다. 하나의 엔티티로서 composite 요소를 다시 모델링하려고 시도하라 - 그러나 자바 모형들이 동일할지라도,
관계형 모형과 영속화 의미들은 여전히 약간 다르다.
</para>
<para>
당신이 하나의 <literal>&lt;set&gt;</literal>을 사용 중이라면, 하나의 composite 요소 매핑은 null 가능한 프로퍼티들을
지원하지 않음을 노트하길 바란다. Hibernate는 객체들을 삭제할 때 하나의 레코드를 식별하는데 각각의 컬럼들 값을 사용해야 하며
(composite 요소 테이블 내에 별도의 프라이머리 키 컬럼이 존재하지 않는다), 그것은 null 값들에 대해서는 불가능하다. 당신은
하나의 composite-요소 내에 not-null 프로퍼티들 만을 사용해야 하거나 하나의 <literal>&lt;list&gt;</literal>,
<literal>&lt;map&gt;</literal>, <literal>&lt;bag&gt;</literal> 또는 <literal>&lt;idbag&gt;</literal>
선택해야 한다.
</para>
<para>
composite 요소에 대한 하나의 특별한 경우는 내포된 <literal>&lt;many-to-one&gt;</literal> 요소를 가진 composite 요소이다.
이같은 매핑은 many-to-many 연관 테이블의 특별한 컬럼들을 composite 요소 클래스로 매핑시키는 것을 당신에게 허용해준다. 다음은
<literal>Order</literal>로부터 <literal>Item</literal>으로의 many-to-many 연관이다. 여기서
<literal>purchaseDate</literal>, <literal>price</literal>, 그리고 <literal>quantity</literal>는 연관의
프로퍼티들이다:
</para>
<programlisting><![CDATA[<class name="eg.Order" .... >
....
<set name="purchasedItems" table="purchase_items" lazy="true">
<key column="order_id">
<composite-element class="eg.Purchase">
<property name="purchaseDate"/>
<property name="price"/>
<property name="quantity"/>
<many-to-one name="item" class="eg.Item"/>
<!-- class attribute is optional -->
</composite-element>
</set>
</class>]]></programlisting>
<para>
물론, 양방향 연관 네비게이션의 경우, 다른 측 상에 있는 purchase에 대한 참조가 존재할 수 없다. 컴포넌트들이 값(value) 타입들이고
공유된 참조들을 허용하지 않음을 기억하라. 하나의 <literal>Purchase</literal><literal>Order</literal>를 가진 set
내에 있을 수 있지만, 그것은 동시에 <literal>Item</literal>에 의해 참조될 수 없다.
</para>
<para>심지어 세겹의(또는 네 겹의, 기타) 연관들이 가능하다:</para>
<programlisting><![CDATA[<class name="eg.Order" .... >
....
<set name="purchasedItems" table="purchase_items" lazy="true">
<key column="order_id">
<composite-element class="eg.OrderLine">
<many-to-one name="purchaseDetails class="eg.Purchase"/>
<many-to-one name="item" class="eg.Item"/>
</composite-element>
</set>
</class>]]></programlisting>
<para>
composite 요소들은 다른 엔티티들에 대한 연관들과 동일한 구문을 사용하여 질의들 내에 나타날 수도 있다.
</para>
</sect1>
<sect1 id="components-asmapindex">
<title>Map 인덱스들로서 컴포넌트들</title>
<para>
<literal>&lt;composite-map-key&gt;</literal> 요소는 당신에게 하나의 컴포넌트 클래스를 하나의 <literal>Map</literal>
키로서 매핑시키도록 한다. 당신은 컴포넌트 클래스 상에서 <literal>hashCode()</literal><literal>equals()</literal>
정확하게 오버라이드 시키도록 하라.
</para>
</sect1>
<sect1 id="components-compositeid" revision="1">
<title>composite 식별자들로서 컴포넌트들</title>
<para>
당신은 하나의 컴포넌트를 하나의 엔티티 클래스에 대한 하나의 식별자로서 사용할 수도 있다. 당신의 컴포넌트 클래스는 어떤 사양들을
충족시켜야 한다:
</para>
<itemizedlist spacing="compact">
<listitem>
<para>
그것은 <literal>java.io.Serializable</literal>을 구현해야 한다.
</para>
</listitem>
<listitem>
<para>
그것은 composite 키 등가(equality)에 대한 데이터베이스 개념과 일치되게, <literal>equals()</literal>
<literal>hashCode()</literal>를 다시 구현해야 한다.
</para>
</listitem>
</itemizedlist>
<para>
<emphasis>노트: Hibernate3에서, 두 번째 사양은 Hibernate의 절대적으로 엄격한 사양이 아니다.
그러나 아무튼 그것을 행하라.</emphasis>
</para>
<para>
당신은 compsite 키들을 생성시키는데 <literal>IdentifierGenerator</literal>를 사용할 수 없다. 대신에 어플리케이션은
그것 자신의 식별자들을 할당해야 한다.
</para>
<para>
통상의 <literal>&lt;id&gt;</literal> 선언 위치에 (내포된 <literal>&lt;key-property&gt;</literal> 요소들을 가진)
<literal>&lt;composite-id&gt;</literal> 태그를 사용하라. 예를 들어, <literal>OrderLine</literal> 클래스는
<literal>Order</literal>의 (composite) 프라이머리 키에 의존하는 프라이머리 키를 갖는다.
</para>
<programlisting><![CDATA[<class name="OrderLine">
<composite-id name="id" class="OrderLineId">
<key-property name="lineId"/>
<key-property name="orderId"/>
<key-property name="customerId"/>
</composite-id>
<property name="name"/>
<many-to-one name="order" class="Order"
insert="false" update="false">
<column name="orderId"/>
<column name="customerId"/>
</many-to-one>
....
</class>]]></programlisting>
<para>
이제 <literal>OrderLine</literal> 테이블을 참조하는 임의의 foreign 키들이 또한 compsite이다. 당신은 다른 클래스들에 대한
당신의 매핑들 속에 이것을 선언해야 한다. <literal>OrderLine</literal>에 대한 하나의 연관은 다음과 같이 매핑될 것이다:
</para>
<programlisting><![CDATA[<many-to-one name="orderLine" class="OrderLine">
<!-- the "class" attribute is optional, as usual -->
<column name="lineId"/>
<column name="orderId"/>
<column name="customerId"/>
</many-to-one>]]></programlisting>
<para>
(<literal>&lt;column&gt;</literal> 태그가 모든 곳에서 <literal>column</literal> 속성에 대한 대안임을 노트하라.)
</para>
<para>
<literal>OrderLine</literal>에 대한 <literal>many-to-many</literal> 연관은 또한 composite foreign 키를 사용한다:
</para>
<programlisting><![CDATA[<set name="undeliveredOrderLines">
<key column name="warehouseId"/>
<many-to-many class="OrderLine">
<column name="lineId"/>
<column name="orderId"/>
<column name="customerId"/>
</many-to-many>
</set>]]></programlisting>
<para>
<literal>Order</literal>에서 <literal>OrderLine</literal>들의 콜렉션이 사용될 것이다:
</para>
<programlisting><![CDATA[<set name="orderLines" inverse="true">
<key>
<column name="orderId"/>
<column name="customerId"/>
</key>
<one-to-many class="OrderLine"/>
</set>]]></programlisting>
<para>
(통상적으로 <literal>&lt;one-to-many&gt;</literal> 요소는 컬럼들을 선언하지 않는다.)
</para>
<para>
만일 <literal>OrderLine</literal> 자체가 하나의 콜렉션을 소유할 경우, 그것은 또한 하나의 composite foreign 키를 갖는다.
</para>
<programlisting><![CDATA[<class name="OrderLine">
....
....
<list name="deliveryAttempts">
<key> <!-- a collection inherits the composite key type -->
<column name="lineId"/>
<column name="orderId"/>
<column name="customerId"/>
</key>
<list-index column="attemptId" base="1"/>
<composite-element class="DeliveryAttempt">
...
</composite-element>
</set>
</class>]]></programlisting>
</sect1>
<sect1 id="components-dynamic" revision="1">
<title>동적인 컴포넌트들</title>
<para>
당신은 <literal>Map</literal> 타입의 프로퍼티를 매핑시킬 수도 있다:
</para>
<programlisting><![CDATA[<dynamic-component name="userAttributes">
<property name="foo" column="FOO" type="string"/>
<property name="bar" column="BAR" type="integer"/>
<many-to-one name="baz" class="Baz" column="BAZ_ID"/>
</dynamic-component>]]></programlisting>
<para>
<literal>&lt;dynamic-component&gt;</literal> 매핑의 의미는 <literal>&lt;component&gt;</literal>와 동일하다.
이런 종류의 매핑의 장점은 배치 시에 단지 매핑 문서를 편집함으로써 그 bean의 실제 프로퍼티들을 결정하는 가용성이다. 매핑 문서에
대한 런타임 처리는 또한 DOM 파서를 사용하여 가능하다. 더 좋게는 당신이 <literal>Configuration</literal> 객체를 통해
Hibernate의 구성-시 메타모형에 접근할 수 있다(그리고 변경시킬 수 있다)
</para>
</sect1>
</chapter>