'매핑'에 해당되는 글 3건

  1. 2010.06.04 Hibernate n-1 관계
  2. 2010.06.04 Hibernate 1-1관계
  3. 2010.05.31 클래스 - 테이블 매핑
n-1관계를 표현할때는
  • 외부 키를 이용한 n-1 관계
  • 조인 테이블을 이용한 n-1 관계
외부키를 이용한 n-1 관계

Order 와 Product 클래스는 n-1  관계를 갖는다.
<many-to-one> 태그를 사용하여, Order클래스에서 Product 클래스로 부터 n-1관계를 표시할 수 있다.

<class name="Product" table="PRODUCT">
  <id name="id" column="ID">
    <generator class="identity" />
  </id>
..
<class name="Order" table="ORDERINFO">
  <id name="id" column=ID">
    <generator class="identity" />
  </id>

  <many-to-one name="product" class="Product" column="PRODUCTID" />
  <component name="address" class="Address"">
  ..
  </component>
</clss>

죠인 테이블을  이용한 n-1 관계
조인 테이블에 있는 두 칼럼이 모두 주요키로 사용되며, 조인 테이블의 각 칼럼은 각각 ITEM테이블과 SELLER  테이블의 주요키를 참조하는 외부 키이다.
조인 테이블을 이용, n-1의 관계를 매핑할 때에는 조인 테이블을 이용한 1-1의 관계를 매핑할때와 마찬가지로 <join>  태그 사용
<class name="item" table="ITEM">
  <id name="id' column="ID">
    <generator clss="identity" />
  </id>
  <join table="ITEM_SELLER" optional="true">
    <key coulmn="ITEMID" />
    <many-to-one name="seller" column="SELLTERID" />
  </join>
</class>

<class name="Seller" table="SELLDER">
  <id name="id" column="ID">
    <generator class="identity" />
  </id>
</class>
조인 테이블을 이용한 1-1 관계의 경우와 비슷.
<many-to-one>에서 unique  속성을 명시하지 않는 것이 차이점. n-1관계이기 때문에 동일한 값의 SELLERID 칼럼에 여러
ITEMID 값이 존재 할수 있다. -> SELLERID는 유일한 값을 갖지 않으므로 unique 속성을 명시하지 않음.



저작자 표시
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by 영겁회귀
관계에 따른 매핑 방법
  • 1-1 관계
  • n-1 관계
1-1 관계
세가지 방법
  1. 동일한 키값을 갖는 경우
  2. 한 테이블의 주요 키 값을 다른 테이블에서 외부 키로 참조하는 경우
  3. 조인 테이블을 이용하는 경우
동일한 키 값을 갖는 1-1 관계
주요키를 사용한 1-1연관의 예
public class Article { //연관의 부모가 되는 클래스
  private int id;
  private String title;
  private ArticleDetail detail;
}

public class ArticleDetail { //연관의 자식이 되는 클래스
  private int id;
  private Article article;
  private String content;
}
ArticleDetail은 Article이 없다면 존재할수 없지만,
Article이 삭제된다도 함께 삭제 되지 않는다.
<class name="Article" table="ARTICLE">
  <id name="id" column="ID">
    <generator class="identity" />
  </id>
  ...
  <one-to-one name="detail" class="ArticleDetail"
    cascade="save-update,delete" />
</class>
cascade속성, Article객체가 저장(수정)될때 1-1연관으로 설정한 detail객체도 함께 저장(수정)된다.
cascade속성을 명시하지 않으면 Article이 저장되어도 ArticleDetail은 저장되지 않는다.
save-update 로 명시하지 않은 경우 Article과 연관된 ArticleDetail  객체를 저장하기 위해서는 Session.save(), Session.update()
에 ArticleDetail객체를 전달해야함.

자식에서 부모로의 1-1연관
<class name="ArticleDetail" table="ARTICLE_DETAIL">
  <id name="id" column="ARTICLE_ID">
    <generator class="foreign">
      <param name="property">article</param>
    </gegerator>
  </id>
  <one-to-one name="article" class="Article" constrained="true" />
  ..
</class>
cascade대신 constrained 속성사용.
자식은 부모의 키값을 자신의 키 값으로 사용함. -> 식별자 생성기로 ' foreign'를 사용.
constrained="true"는 프로퍼티의 키값이 외부 키에 의해 제약받는것을 의미. -> "article" 프로퍼티의 키값을 ArticleDetail의 키값으로 사용한다는 뜻.

1-1 연관을 맺은후
Article article = new Article();
ArticleDetail detail = new ArticleDetail();
article.setDetail(detail);
detail.setArticle(detail);
..
session.save(article);
cascade 속성을 명시하지 않으면, Article객체가 저장될때 ArticleDetail은 저장되지 않는다.
Article만 읽어와도 ArtileDetail를 사용할수 있다.
Article article = (Article) session.get(Article.class, new Integer(10));
ArticleDetail detail = article.getArticleDetail();

cascade속성에 delete가 포함되어있다면 Article를 삭제하면  1-1관계를 맺고있는 ArticleDetail 도 삭제된다.
Article article = (Article) session.get(Article.class, new Integer(10));
session.delete(article);

위 코드는 다음같이 두개의 쿼리가 실행된다.
delete from ARTICLE_DETAIL where ARTICLE_ID = 10
delete from ARTICLE where ID = 10

외부 키를 사용한 1-1 관계
MEMBER와 MEMBER_DETAIL은 다른 키값을 가지는 대신
MEMBER는 외부 키를 이용해   MEMBER_DETAIL 과 1-1연관을 맺는다.
<class name="Member" table="MEMBER">
  <id name="id" coloumn="ID">
    <genrator class="identity" />
  </id>
  <property name="usernmae' column="USERNAME" />
  <many-to-one name="detail"
    class="MemberDetail"
    column="MEMBER_DETAILEID"
    unique="true"
    cascade="save-update, delete" />
</class>

<class name="MemberDetail" table="MEMBER_DETAIL">
  <id name="id" column="ID">
    <generator class="identity" />
  </id>
  ...
  <one-to-one name="member" class="Member" property-ref="detail" />
</class>
<many-to-one> 은  detail 프로퍼티가 MEMBER_ARTICLEID칼럼과 매핑되며 MEMBER_DETAILID 칼럼은 MemberDetail 클래스와 연관된다고 지정하고 있음.
MemberDetail 클래스는 MEMBER_DETAIL 테이블과 매핑되므로, 결국 MEMBER 테이블의 MEMBER_DETAILEID 칼럼은 MEMBER_DETAIL 테이블의  ID칼럼을 참조하게 된다.

Member 객체가 저장/삭제될때 MemberDetail  객체도 저장/삭제야 하므로 cascade 속성을 save-update, delete로 지정.
하나의 Member객체는 고유의 MemberDetail 객체와 연관되므로 unique 속성을  "true"로 지정.

조인 테이블을 이용한 1-1관계

DELIVERY_ORDER 테이블의 제약
DELIVERYID - DEVLIERY 테이블의 주요키로 참조하며, 이칼럼 자체는 주요키가 된다.
ORDERINFO - ORDER 테이블의 주요키를 외부 키로 참조하며 1-1연관의 의미를 지키기 위해 제약 조건을 갖는다.

DELIVERY  테이블에서 ORDER 테이블로의 관계가 1-1이므로 Deliver 클래스는 Order타입의 필드를 포함하게 된다.
public class Delivery {
  private Integer id;
  private Order order;
  ..
}

조인 테이블을 사용하여, 1-1관계를 명시한 경우
<class name="Delivery" table="DELIVERY">
  <id name="id" column="ID">....</id>
 
  <join table="DELIVERY_ORDER" optional="true"
    <key coulumn="DELIVERYID" />
    <many-to-one name="order"
      column="ORDERINFOID" not-null="true" unique="true" />
  </join>
</class>

<class name="Order" table="ORDERINFO">....</class>
<join> 태그의 table 속성은 조인 테이블의 이름을 명시.
<key> 태그의 column속성은 조인 테이블에서 Delivery  클래스와 연관된 칼럼을 명시. (DELIVERYID)
<many-to-one>은 Delivery 클래스에서  Order클래스로의 연관 정보를 입력.
1-1 관계를 유지하기위해 unique속성을 true로 지정.
사용은 다음과 같이.
Order order = new Order();
Delivery delivery = new Delivery();
delivery.setOrder(order);

session.save(order);
session.save(delivery);

미리 생성된 Order객체를 구한뒤, Delivery  객체와 연관지어 저장할수 있다.
Order order = session.get(Order.class, 10);
Delivery delivery = new Delivery();
delivery.setOrder(order);
session.save(delivery);

<many-to-one> 태그의 not-null속성을   true로 지정하였으므로, order 프로퍼티의 값을 지정하지 않고
delivery객체를 저장하면 제약조건 위반 에러가 발생한다.
Delivery delivery = new Delivery();
session.save(delivery); // not-null 제약조건위반

<join> 태그의 optional속성 값을  true 로 하며, <join>태그를 통해 연관된 프로퍼티의 값이 null이 아닌 경우에만
조인 테이블에 값을 저장한다.
저작자 표시
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by 영겁회귀
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping schema="USR1" package="pe.lucene.hibernate">
  <class name="User" table="User">
    <id name="id" column="USER_ID">
      <generator name="identity" />
    </id>
    <property name="title" coulmn="TITLE" />
    ....
  </class>

  <class name="pelucene.hbernate.Hobby" table="Hobby">
  ...
  </class>
</hibernate-mapping>

<hibernate-mapping> 의 속성은 모두 선택 사항.
schema - 데이터베이스 스키마 이름
catalog - 데이터베이스 카탈로그 이름
package - <class> 태그에서 완전한 클래스 이름을 명시하지 않을때 사용

<hibernate-mapping> 는 1개이상의 <class>를 가질수 있다.
<class>의 주요 속성
name - 클래스이름
table - 테이터 베이스 테이블 이름
<hibernate-mapping schema="BBS0" package="...">
  <class name="Board" table="BOARD" schema="BBS1">
  ....
  </class>
</hibernate-mapping>
BBS0.BOARD가 아니라 BBS1.BOARD 사이의 매핑을 의미한다.

컬럼 수가 많아서 값이 존재하거나, 변경된 칼럼에 대해서만 쿼리를 생성하기 원할때 dynamic-insert, dynamic-upate속성을 true로.
<class name="Product"
  dynamic-insert="true"
  dynamic-update="true">
  ...
</class>
dynamic-insert가 true일때는 값이 null인 프로퍼티는 INSERT쿼리가 생성될대 포함되지 않는다.
dynamic-update가 true일 경우 값이 변경되지 않는 프로퍼티는 쿼리에 포함시키지 않는다.
따라서 객체의 값이 변경될 경우 변경된 프로퍼터에 대해서만 UPDATE쿼리를 수행하게 된다.

식별자 필드 매핑
<class name="Article" table="ARTICLE"
  <id name="id" column="ARTICLEID" type="long">
    <generator class="identity" />
  </id>
  ....
</class>
주요키(Primary Key) 컬람에 대한 매핑은 <id>를 사용
<id>를 <generator>와 함께 사용.
<id>의 name -> 프로퍼티 이름, column -> 데이블 주요키 컬럼 이름 , type -> 프로퍼티 타입 (하이버네이트에서 제공하는 타입)
 생성기이름 설명
 identity mysql, DB2, MS sql, Sybase, HypersonicSQL의 식별자 칼럼지원, 리턴타입은 int , long, short
 sequence  오라클,DB2, PostegeSQL에서 사용하는 시퀀스를 사용. 리턴 타입 long,short, int
 hilo  hi/lo 알고리즘을 사용하여 short,long,int 타입의 키를 생성.hi값은 지정한 테이블의 칼럼으로부터 가져온다
 native  하위 데이타 베이스가 제공하는 기능에 따라 indentity, sequence, hilo 생성기 중에서 한가지를 선택한다.
 assigned  자동으로 키 값을 생성하지 않고, 코드에서 직접 키 값을 지정한다.
 increment 하이버네이트가 1씩 증가된 키 값을 할당한다.
 guid  ms sql과 mysql에서 데이터베이스 생성한 guid 문자열을 키값으로 사용한다.
 uuid 128비트 UUID알고리즘을 사용 string타입의 키를 생성, 생성된 문자열은 32글자의 16진법으로 인코딩되어 표시된다
 seqhilo hilo생성기와 동일하다. 차이점은 주어진 데이터베이스 시퀀스로부터 hi값을 가져온다는 것
foreign 연관된 객체의 식별자를 사용, 일반적으로 <one-to-one> 주요 키 연관에서 사용된다.

identity 생성기 - mysql의 auto_increment 칼럼과 같이 DBMS가 제공하는 식별자 칼럼을 지원
create table ARTICLE (
  ARTICLEID int not null auto_increment,
  ..
)

<class name="Article" table="ARTICLE">
  <generator class="identity" />
  ...
</class>

Article article1 = new Article();
Article article2 = new Article();
...
session.save(article1);
session.save(article2);

session.getTransaction().commit();

//article1.getId() + 1 == article2.getId() : true

sequence 생성기
오라클의 시퀀스와 같은 것으로부터 읽어온 값을 식별자로 사용한다.
사용할 시퀀스의 이름을 파라미터로 받아온다
<class name="Article" table="ARTICLE">
  <id name="id" column="ARTICLE_ID" type="int">
    <generator class="sequence">
      <param name="sequence">SEQ_ARTICLE</param>
    </generator>
  </id>
  ..
</class>
객체를 테이블에 저장할 때, SEQ_ARTICLE 시퀀스로부터 값을 읽어와 id 프로퍼티의 값으로 사용하게 된다.

assigned 생성기
자동으로 키를 생성하지 않고, 객체를 저장하기 전에 코드에서 직접 키 값을 지정할때 사용된다.
<class name="Member" table="MEMBER">
  <id name="email" column="MEMBER_EMIAL" type="string">
    <generator class="assigened" />
  </id>
  ..
</class>

increment 생성기
키값을 하이버네이트가 1씩 증가시켜 준다.
최초에 값 생성이 필요할 때 다음과 같은 쿼리를 실행하여 테이블로부터 현재 저장된 키 값으리 최대값을 구한다.
select max(ID) from ARTICLE
최대 키 값을 읽어 오면, 이후부터는 메모리에서 값을 1씩 증가시킨다. 매번 데이타베이스 테이블을 조회하는 것이 아니기 때문에, 분산환경에서는 increment 생성기를 사용해서는 안된다.


일반 필드 매핑

property 태그를 사용
<class name='pe.lucene.haibernate.Article" table="ARTICLE" ..>
  ..
  <proeprty name="title" column="TITLE" type="string" />
  ..
</class>
프로퍼티의 이름이 칼럼이름과 동일하다면 column 속성을 사용하지 않아도 된다.
<property name="title" type="string" />
칼럼부분을 <column> 태그로 사용하여 명시할수 있다.
<property name="title" type="string">
  <column name="TITLE" />
</property>
type속성을 명시하지 않을 경우에는 하이버네이트가 자동으로 타입을 감지하여 알맞게 처리한다.
그러나 완벽하지 않으므로 매핑 타입을 지정해주는 것이 좋다.

insert, update - 쿼리 실행시 프로퍼티 포함여부
<property name="lastModified" column="LAST_MODIFIED"
  insert="false" update="true" generated="always" />
자동으로 값이 생성되는 칼럼으로 매핑퇴는 프로퍼티의 경우는 INSERT쿼리나 UPDATE에 포함시킬 필요가 없으니 false로 지정하여 목록에서 제외할수 있다.

데이터베이스가 값을 생성하는 컬럼의 명시
<property name="lastModified" ... generated="always" />
update되었다고 가정했을때 컬럼의 값을 바뀌었지만 자바 객체의 값은 바뀌지 않았으므로 올바른값을 유지 할수 없다.
generated 속성을 사용하여 하이버네이트로 하여금 해당 칼럼으로 부터 값을 읽어오게 할 수 있다.
INSERT나 UPDATE 쿼리를 실행한후 칼럼의 값을 테이블에서 읽어와 객체에 반영한다.
generted 값을 insert로 하면 INSERT 쿼리를 실행할때만 값을 읽어온다.

계산된 값 매핑
<property name="average" fomula="SUM / TOTAL_COUNT" />
칼럼의 값을 사용하여 계산된 결과를 프로퍼티에 저장.
TOAL_COUNT 칼럼과 SUM칼럼을 사용하여 구한 평균값을 프로퍼트에 저장
객체를 로딩할때마가 매번 실행됨. INSERT쿼리나 UPDATE쿼리가 실행될때에는 사용되지 않는다

프로퍼티 접근 모드 지정
<property name="title" />
기본적으로 자바 빈 스타일의 프로퍼티 사용
setTitle(), getTitle()이 정의되어 있어야 한다.

<property name="title" column="TITLE" access="field" />
field로 지정한 경우 자바 빈 스타일의 get,set메서드를 구현할 필요는 없으며, 다음과 같은 필드 정의만 필요 (private로 선언되어도 상관없음)
public class Article {
  private String title;
  ..
}
access의 기본값은 "property"로 자바 빈 스타일의 get/set 메소드가 필요한 방식이다.
acesss 속성을  지정해야될 칼럼이 많은 경우는 default-access 속성을 사용할수 있다.
<hibernate-mapping default-access="field" ...>
  <class ..>
    <property name="title" />
    <property name="name" />
    <property name="content" acess="property" />
    ....
  </class>
</hibernate-mapping>


저작자 표시
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by 영겁회귀

티스토리 툴바