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
460 lines
21 KiB
XML
460 lines
21 KiB
XML
<chapter id="inheritance">
|
|
<title>상속 매핑</title>
|
|
|
|
<sect1 id="inheritance-strategies" revision="3">
|
|
<title>세 가지 방도들</title>
|
|
|
|
<para>
|
|
Hibernate는 세 가지 기본적인 상속 매핑 방도들을 지원한다:
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
table per class hierarchy
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
table per subclass
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
table per concrete class
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
게다가 Hibernate는 네 번째의 약간 다른 종류의 다형성을 지원한다:
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
implicit polymorphism(함축적인 다형성)
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
동일한 상속 계층구조의 다른 가지들에 대해 다른 매핑 방도들을 사용하는 것이 가능하고, 그런 다음 전체 계층 구조를 가로질러
|
|
다형성을 성취하는데 함축적인 다형성을 사용하라. 하지만 Hibernate는 동일한 루트 <literal><class></literal> 요소
|
|
하에서 <literal><subclass></literal> 그리고 <literal><joined-subclass></literal> 그리고
|
|
<literal><union-subclass></literal> 매핑들을 혼합하는 것을 지원하지 않는다. 동일한 <literal><class></literal>
|
|
요소 하에서 <literal><subclass></literal> 요소와 <literal><join></literal> 요소를 결합시킴으로써
|
|
table per hierarchy 방도와 table per subclass 방도를 함께 혼합시키는 것이 가능하다(아래를 보라).
|
|
</para>
|
|
|
|
<para>
|
|
별도의 매핑 문서 내에, <literal>hibernate-mapping</literal> 바로 밑에 <literal>subclass</literal>,
|
|
<literal>union-subclass</literal>, 그리고 <literal>joined-subclass</literal> 매핑들을 정의하는 것이
|
|
가능하다. 이것은 단지 하나의 새로운 매핑 파일을 추가시켜서 하나의 class 계층구조를 확장하는 것을 당신에게 허용해준다.
|
|
당신은 subclass 매핑 내에 앞서 매핑된 슈퍼클래스를 명명하여 <literal>extends</literal> 속성을 지정해야 한다.
|
|
노트 : 명백하게 이 특징은 매핑 문서들의 순서를 중요하게끔 만들었다. Hibernate3 이후로, 매핑 파일들의 순서는 extends 키워드를
|
|
사용할 때 상관없다. 하나의 매핑 파일 내의 순서는 여전히 서브클래스들에 앞서 슈퍼클래스들을 정의하는데 여전히 필요하다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[
|
|
<hibernate-mapping>
|
|
<subclass name="DomesticCat" extends="Cat" discriminator-value="D">
|
|
<property name="name" type="string"/>
|
|
</subclass>
|
|
</hibernate-mapping>]]></programlisting>
|
|
|
|
|
|
<sect2 id="inheritance-tableperclass" >
|
|
<title>Table per class hierarchy</title>
|
|
|
|
<para>
|
|
우리가 <literal>CreditCardPayment</literal>, <literal>CashPayment</literal>, <literal>ChequePayment</literal>
|
|
구현자들을 가진 하나의 인터페이스 <literal>Payment</literal>를 갖고 있다고 가정하자. table per hierarchy 매핑은
|
|
다음과 같을 것이다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<class name="Payment" table="PAYMENT">
|
|
<id name="id" type="long" column="PAYMENT_ID">
|
|
<generator class="native"/>
|
|
</id>
|
|
<discriminator column="PAYMENT_TYPE" type="string"/>
|
|
<property name="amount" column="AMOUNT"/>
|
|
...
|
|
<subclass name="CreditCardPayment" discriminator-value="CREDIT">
|
|
<property name="creditCardType" column="CCTYPE"/>
|
|
...
|
|
</subclass>
|
|
<subclass name="CashPayment" discriminator-value="CASH">
|
|
...
|
|
</subclass>
|
|
<subclass name="ChequePayment" discriminator-value="CHEQUE">
|
|
...
|
|
</subclass>
|
|
</class>]]></programlisting>
|
|
|
|
<para>
|
|
정확히 하나의 테이블이 필요하다. 이 매핑 방도에는 다음의 하나의 큰 제약이 존재한다: <literal>CCTYPE</literal>과 같이,
|
|
서브 클래스들에 의해 선언된 컬럼들은 <literal>NOT NULL</literal> 컨스트레인트들을 가질 수 없다.
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="inheritance-tablepersubclass">
|
|
<title>Table per subclass</title>
|
|
|
|
<para>
|
|
table per subclass 매핑은 다음과 같을 것이다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<class name="Payment" table="PAYMENT">
|
|
<id name="id" type="long" column="PAYMENT_ID">
|
|
<generator class="native"/>
|
|
</id>
|
|
<property name="amount" column="AMOUNT"/>
|
|
...
|
|
<joined-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
|
|
<key column="PAYMENT_ID"/>
|
|
<property name="creditCardType" column="CCTYPE"/>
|
|
...
|
|
</joined-subclass>
|
|
<joined-subclass name="CashPayment" table="CASH_PAYMENT">
|
|
<key column="PAYMENT_ID"/>
|
|
...
|
|
</joined-subclass>
|
|
<joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
|
|
<key column="PAYMENT_ID"/>
|
|
...
|
|
</joined-subclass>
|
|
</class>]]></programlisting>
|
|
|
|
<para>
|
|
네 개의 테이블들이 필요하다. 세 개의 서브클래스 테이블들은 슈퍼클래스 테이블에 대한 프라이머리 키 연관들을 갖는다
|
|
(따라서 그 관계형 모형은 실제로 one-to-one 연관이다).
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="inheritance-tablepersubclass-discriminator" revision="2">
|
|
<title>discriminator를 사용하는, table per subclass</title>
|
|
|
|
<para>
|
|
table-per-subclass에 대한 Hibernate의 구현은 discriminator(판별자) 컬럼을 필요로 하지 않음을 노트하라.
|
|
다른 객체/관계형 매핑기들은 슈퍼클래스 테이블 속에 하나의 타입 판별자 컬럼을 필요로 하는 table-per-subclass에 대한 다른 구현을
|
|
사용한다. Hibernate에 의해 채택된 접근법은 구현하기가 훨씬 더 어렵지만 관계형 관점에서는 아마 틀림없이 보다 더 정확하다.
|
|
만일 당신이 table per subclass 방도에 대해 하나의 판별자 컬럼을 사용하고 싶다면, 당신은 다음과 같이
|
|
<literal><subclass></literal>와 <literal><join></literal>의 사용을 결합시킬 수도 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<class name="Payment" table="PAYMENT">
|
|
<id name="id" type="long" column="PAYMENT_ID">
|
|
<generator class="native"/>
|
|
</id>
|
|
<discriminator column="PAYMENT_TYPE" type="string"/>
|
|
<property name="amount" column="AMOUNT"/>
|
|
...
|
|
<subclass name="CreditCardPayment" discriminator-value="CREDIT">
|
|
<join table="CREDIT_PAYMENT">
|
|
<key column="PAYMENT_ID"/>
|
|
<property name="creditCardType" column="CCTYPE"/>
|
|
...
|
|
</join>
|
|
</subclass>
|
|
<subclass name="CashPayment" discriminator-value="CASH">
|
|
<join table="CASH_PAYMENT">
|
|
<key column="PAYMENT_ID"/>
|
|
...
|
|
</join>
|
|
</subclass>
|
|
<subclass name="ChequePayment" discriminator-value="CHEQUE">
|
|
<join table="CHEQUE_PAYMENT" fetch="select">
|
|
<key column="PAYMENT_ID"/>
|
|
...
|
|
</join>
|
|
</subclass>
|
|
</class>]]></programlisting>
|
|
|
|
<para>
|
|
선택적인 <literal>fetch="select"</literal> 선언은 슈퍼클래스를 질의할 때 outer join을 사용하여
|
|
<literal>ChequePayment</literal> 서브클래스 데이터를 페치시키지 않도록 Hibernate에게 알려준다.
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="inheritance-mixing-tableperclass-tablepersubclass">
|
|
<title>table per class hierarchy와 table per subclass를 혼합하기</title>
|
|
|
|
<para>
|
|
당신은 이 접근법을 사용하여 table per hierarchy 방도와 table per subclass 방도를 혼합시킬 수 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<class name="Payment" table="PAYMENT">
|
|
<id name="id" type="long" column="PAYMENT_ID">
|
|
<generator class="native"/>
|
|
</id>
|
|
<discriminator column="PAYMENT_TYPE" type="string"/>
|
|
<property name="amount" column="AMOUNT"/>
|
|
...
|
|
<subclass name="CreditCardPayment" discriminator-value="CREDIT">
|
|
<join table="CREDIT_PAYMENT">
|
|
<property name="creditCardType" column="CCTYPE"/>
|
|
...
|
|
</join>
|
|
</subclass>
|
|
<subclass name="CashPayment" discriminator-value="CASH">
|
|
...
|
|
</subclass>
|
|
<subclass name="ChequePayment" discriminator-value="CHEQUE">
|
|
...
|
|
</subclass>
|
|
</class>]]></programlisting>
|
|
|
|
<para>
|
|
이들 매핑 방도들 중 어떤 것에 대해, 루트 <literal>Payment</literal> 클래스에 대한 하나의 다형성 연관은
|
|
<literal><many-to-one></literal>을 사용하여 매핑된다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<many-to-one name="payment" column="PAYMENT_ID" class="Payment"/>]]></programlisting>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="inheritance-tableperconcrete" revision="2">
|
|
<title>Table per concrete class</title>
|
|
|
|
<para>
|
|
우리가 table per concrete class 방도 매핑에 대해 취할 수 있는 두 가지 방법들이 존재한다. 첫 번째는
|
|
<literal><union-subclass></literal>를 사용하는 것이다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<class name="Payment">
|
|
<id name="id" type="long" column="PAYMENT_ID">
|
|
<generator class="sequence"/>
|
|
</id>
|
|
<property name="amount" column="AMOUNT"/>
|
|
...
|
|
<union-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
|
|
<property name="creditCardType" column="CCTYPE"/>
|
|
...
|
|
</union-subclass>
|
|
<union-subclass name="CashPayment" table="CASH_PAYMENT">
|
|
...
|
|
</union-subclass>
|
|
<union-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
|
|
...
|
|
</union-subclass>
|
|
</class>]]></programlisting>
|
|
|
|
<para>
|
|
세 개의 테이블들이 슈퍼클래스들에 대해 수반된다. 각각의 테이블은 상속된 프로퍼티들을 포함하여, 그 클래스의 모든 프로퍼티들에 대한 컬럼들을 정의한다.
|
|
</para>
|
|
|
|
<para>
|
|
이 접근법의 제약은 만일 하나의 프로퍼티가 슈퍼클래스 상으로 매핑될 경우, 그 컬럼 이름이 모든 서브클래스 테이블들 상에서 같아야 한다는
|
|
점이다.(장래의 Hibernate 배포본에서 우리는 이 제약을 풀 수도 있다.) identity 생성기 방도는 union 서브클래스 상속에서 허용되지
|
|
않으며, 진정 프라이머리 키 시드는 하나의 계층구조의 모든 unioned 서브클래스들을 가로질러 공유되어야 한다.
|
|
</para>
|
|
|
|
<para>
|
|
만일 당신의 슈퍼클래스가 abstract일 경우에, 그것을 <literal>abstract="true"</literal>로 매핑하라.
|
|
물론 만일 그것이 abstract가 아닐 경우, 추가적인 테이블(위의 예제에서는 디폴트로 <literal>PAYMENT</literal>)이
|
|
슈퍼클래스의 인스턴스들을 소유하는데 필요하다.
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="inheritance-tableperconcreate-polymorphism">
|
|
<title>함축적인 다형성을 사용하는, table per concrete class</title>
|
|
|
|
<para>
|
|
대안적인 접근법은 함축적인 다형성을 사용하는 것이다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
|
|
<id name="id" type="long" column="CREDIT_PAYMENT_ID">
|
|
<generator class="native"/>
|
|
</id>
|
|
<property name="amount" column="CREDIT_AMOUNT"/>
|
|
...
|
|
</class>
|
|
|
|
<class name="CashPayment" table="CASH_PAYMENT">
|
|
<id name="id" type="long" column="CASH_PAYMENT_ID">
|
|
<generator class="native"/>
|
|
</id>
|
|
<property name="amount" column="CASH_AMOUNT"/>
|
|
...
|
|
</class>
|
|
|
|
<class name="ChequePayment" table="CHEQUE_PAYMENT">
|
|
<id name="id" type="long" column="CHEQUE_PAYMENT_ID">
|
|
<generator class="native"/>
|
|
</id>
|
|
<property name="amount" column="CHEQUE_AMOUNT"/>
|
|
...
|
|
</class>]]></programlisting>
|
|
|
|
<para>
|
|
어느 곳에서도 우리가 명시적으로 <literal>Payment</literal> 인터페이스를 언급하지 않음을 주목하라.
|
|
또한 <literal>Payment</literal>의 프로퍼티들이 서브클래스들 각각에서 매핑된다는 점을 주목하라.
|
|
만일 당신이 중복을 피하고자 원한다면, XML 엔티티들을 사용하는 것을 고려하라(예를 들어 매핑에서
|
|
<literal>DOCTYPE</literal> 선언과 <literal>&allproperties;</literal>에서
|
|
<literal>[ <!ENTITY allproperties SYSTEM "allproperties.xml"> ]</literal>).
|
|
</para>
|
|
|
|
<para>
|
|
이 접근법의 단점은 다형성 질의들을 수행할 때 Hibernate가 생성된 SQl <literal>UNION</literal>들을 생성시키는
|
|
않는다는 점이다.
|
|
</para>
|
|
|
|
<para>
|
|
이 매핑 방도의 경우, <literal>Payment</literal>에 대한 하나의 다형성 연관은 대개 <literal><any></literal>를
|
|
사용하여 매핑된다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<any name="payment" meta-type="string" id-type="long">
|
|
<meta-value value="CREDIT" class="CreditCardPayment"/>
|
|
<meta-value value="CASH" class="CashPayment"/>
|
|
<meta-value value="CHEQUE" class="ChequePayment"/>
|
|
<column name="PAYMENT_CLASS"/>
|
|
<column name="PAYMENT_ID"/>
|
|
</any>]]></programlisting>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="inheritace-mixingpolymorphism">
|
|
<title>함축적인 다형성을 다른 상속 매핑들과 혼합하기</title>
|
|
|
|
<para>
|
|
이 매핑에 대해 주목할 하나 이상의 것이 존재한다. 서브클래스들이 그것들 자신의<literal><class></literal> 요소 내에
|
|
각각 매핑되므로(그리고 <literal>Payment</literal>가 단지 인터페이스이므로), 서브클래스들 각각은 쉽게 또 다른 상속 계층구조의
|
|
부분일 수 있다! (그리고 당신은 <literal>Payment</literal> 인터페이스에 대해 여전히 다형성 질의들을 사용할 수 있다.)
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
|
|
<id name="id" type="long" column="CREDIT_PAYMENT_ID">
|
|
<generator class="native"/>
|
|
</id>
|
|
<discriminator column="CREDIT_CARD" type="string"/>
|
|
<property name="amount" column="CREDIT_AMOUNT"/>
|
|
...
|
|
<subclass name="MasterCardPayment" discriminator-value="MDC"/>
|
|
<subclass name="VisaPayment" discriminator-value="VISA"/>
|
|
</class>
|
|
|
|
<class name="NonelectronicTransaction" table="NONELECTRONIC_TXN">
|
|
<id name="id" type="long" column="TXN_ID">
|
|
<generator class="native"/>
|
|
</id>
|
|
...
|
|
<joined-subclass name="CashPayment" table="CASH_PAYMENT">
|
|
<key column="PAYMENT_ID"/>
|
|
<property name="amount" column="CASH_AMOUNT"/>
|
|
...
|
|
</joined-subclass>
|
|
<joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
|
|
<key column="PAYMENT_ID"/>
|
|
<property name="amount" column="CHEQUE_AMOUNT"/>
|
|
...
|
|
</joined-subclass>
|
|
</class>]]></programlisting>
|
|
|
|
<para>
|
|
다시 한번, 우리는 <literal>Payment</literal>를 명시적으로 언급하지 않는다. 만일 우리가 <literal>Payment</literal>
|
|
인터페이스에 대해 하나의 질의를 실행할 경우-예를 들어, from Payment-, Hibernate는 <literal>CreditCardPayment</literal>
|
|
(와 그것의 서브클래스들, 왜냐하면 그것들 또한 <literal>Payment</literal>를 구현하므로), <literal>CashPayment</literal>
|
|
그리고 <literal>ChequePayment</literal> 인스턴스들을 자동적으로 반환할 것이지만
|
|
<literal>NonelectronicTransaction</literal>의 인스턴스들을 반환하지 않는다.
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="inheritance-limitations">
|
|
<title>제약들</title>
|
|
|
|
<para>
|
|
table per concrete-class 매핑 방도에 대한 "함축적인 다형성" 접근법에는 어떤 제약들이 존재한다.
|
|
<literal><union-subclass></literal> 매핑들에 대해서는 다소 덜 제한적인 제약들이 존재한다:
|
|
</para>
|
|
|
|
<para>
|
|
다음 표는 Hibernate에서 table per concrete-class 매핑들에 대한 제약들, 그리고 함축적인 다형성에 대한 제약들을 보여준다.
|
|
</para>
|
|
|
|
<table frame="topbot">
|
|
<title>상속 매핑들의 특징들</title>
|
|
<tgroup cols='8' align='left' colsep='1' rowsep='1'>
|
|
<colspec colname='c1' colwidth="1*"/>
|
|
<colspec colname='c2' colwidth="1*"/>
|
|
<colspec colname='c3' colwidth="1*"/>
|
|
<colspec colname='c4' colwidth="1*"/>
|
|
<colspec colname='c5' colwidth="1*"/>
|
|
<colspec colname='c6' colwidth="1*"/>
|
|
<colspec colname='c7' colwidth="1*"/>
|
|
<colspec colname='c8' colwidth="1*"/>
|
|
<thead>
|
|
<row>
|
|
<entry>상속 방도</entry>
|
|
<entry>다형성 다대일</entry>
|
|
<entry>다형성 일대일</entry>
|
|
<entry>다형성 일대다</entry>
|
|
<entry>다형성 다대다</entry>
|
|
<entry>다형성 <literal>load()/get()</literal></entry>
|
|
<entry>다형성 질의들</entry>
|
|
<entry>다형성 조인들</entry>
|
|
<entry>Outer 조인 페칭</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry>table per class-hierarchy</entry>
|
|
<entry><literal><many-to-one></literal></entry>
|
|
<entry><literal><one-to-one></literal></entry>
|
|
<entry><literal><one-to-many></literal></entry>
|
|
<entry><literal><many-to-many></literal></entry>
|
|
<entry><literal>s.get(Payment.class, id)</literal></entry>
|
|
<entry><literal>from Payment p</literal></entry>
|
|
<entry><literal>from Order o join o.payment p</literal></entry>
|
|
<entry><emphasis>지원됨</emphasis></entry>
|
|
</row>
|
|
<row>
|
|
<entry>table per subclass</entry>
|
|
<entry><literal><many-to-one></literal></entry>
|
|
<entry><literal><one-to-one></literal></entry>
|
|
<entry><literal><one-to-many></literal></entry>
|
|
<entry><literal><many-to-many></literal></entry>
|
|
<entry><literal>s.get(Payment.class, id)</literal></entry>
|
|
<entry><literal>from Payment p</literal></entry>
|
|
<entry><literal>from Order o join o.payment p</literal></entry>
|
|
<entry><emphasis>지원됨</emphasis></entry>
|
|
</row>
|
|
<row>
|
|
<entry>table per concrete-class (union-subclass)</entry>
|
|
<entry><literal><many-to-one></literal></entry>
|
|
<entry><literal><one-to-one></literal></entry>
|
|
<entry><literal><one-to-many></literal> (for <literal>inverse="true"</literal> only)</entry>
|
|
<entry><literal><many-to-many></literal></entry>
|
|
<entry><literal>s.get(Payment.class, id)</literal></entry>
|
|
<entry><literal>from Payment p</literal></entry>
|
|
<entry><literal>from Order o join o.payment p</literal></entry>
|
|
<entry><emphasis>지원됨</emphasis></entry>
|
|
</row>
|
|
<row>
|
|
<entry>table per concrete class (implicit polymorphism)</entry>
|
|
<entry><literal><any></literal></entry>
|
|
<entry><emphasis>지원되지 않음</emphasis></entry>
|
|
<entry><emphasis>지원되지 않음</emphasis></entry>
|
|
<entry><literal><many-to-any></literal></entry>
|
|
<entry><literal>s.createCriteria(Payment.class).add( Restrictions.idEq(id) ).uniqueResult()</literal></entry>
|
|
<entry><literal>from Payment p</literal></entry>
|
|
<entry><emphasis>지원되지 않음</emphasis></entry>
|
|
<entry><emphasis>지원되지 않음</emphasis></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
</sect1>
|
|
|
|
</chapter>
|