mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-03-03 08:19:15 +00:00
git-svn-id: https://svn.jboss.org/repos/hibernate/trunk/Hibernate3/doc@8466 1b8cb986-b30d-0410-93ca-fae66ebed9b2
375 lines
17 KiB
XML
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><component></literal> 요소는 컴포넌트 클래스의 프로퍼티를 포함되는 엔티티에 대한 역 참조로서 매핑시키는
|
|
<literal><parent></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><element></literal> 태그를 <literal><composite-element></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><nested-composite-element></literal> 태그를 사용하라. 이것은 꽤 신종의 경우-그것들 자체가
|
|
컴포넌트들을 갖고 있는 컴포넌트들의 콜렉션-이다. 이 단계에서 당신은 one-to-many 연관이 더 적절한지를 당신 스스로에게 질문하게
|
|
될 것이다. 하나의 엔티티로서 composite 요소를 다시 모델링하려고 시도하라 - 그러나 자바 모형들이 동일할지라도,
|
|
관계형 모형과 영속화 의미들은 여전히 약간 다르다.
|
|
</para>
|
|
|
|
<para>
|
|
당신이 하나의 <literal><set></literal>을 사용 중이라면, 하나의 composite 요소 매핑은 null 가능한 프로퍼티들을
|
|
지원하지 않음을 노트하길 바란다. Hibernate는 객체들을 삭제할 때 하나의 레코드를 식별하는데 각각의 컬럼들 값을 사용해야 하며
|
|
(composite 요소 테이블 내에 별도의 프라이머리 키 컬럼이 존재하지 않는다), 그것은 null 값들에 대해서는 불가능하다. 당신은
|
|
하나의 composite-요소 내에 not-null 프로퍼티들 만을 사용해야 하거나 하나의 <literal><list></literal>,
|
|
<literal><map></literal>, <literal><bag></literal> 또는 <literal><idbag></literal>을
|
|
선택해야 한다.
|
|
</para>
|
|
|
|
<para>
|
|
composite 요소에 대한 하나의 특별한 경우는 내포된 <literal><many-to-one></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><composite-map-key></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><id></literal> 선언 위치에 (내포된 <literal><key-property></literal> 요소들을 가진)
|
|
<literal><composite-id></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><column></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><one-to-many></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><dynamic-component></literal> 매핑의 의미는 <literal><component></literal>와 동일하다.
|
|
이런 종류의 매핑의 장점은 배치 시에 단지 매핑 문서를 편집함으로써 그 bean의 실제 프로퍼티들을 결정하는 가용성이다. 매핑 문서에
|
|
대한 런타임 처리는 또한 DOM 파서를 사용하여 가능하다. 더 좋게는 당신이 <literal>Configuration</literal> 객체를 통해
|
|
Hibernate의 구성-시 메타모형에 접근할 수 있다(그리고 변경시킬 수 있다)
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
</chapter>
|