** 본 요약은 한빛미디어 '하이버네이트 프로그래밍' 책을 기준으로 작성되어져 있다.

** 본 설명은 바로 따라하기 하기엔 어려움이 있다. 책을 보지 않은 사람에게는 간단히 어떤 기능을 제공하는지 이해하는데 목적을 둔다.

** 하이버네이트 3.2.5.ga 버전, Ant 빌드를 기본적으로 사용한다.


9장 HQL 살펴보기

본 장에서는 HQL 사용법, 그리고 HQL과 SQL의 차이점에 대해 설명합니다. 주요 내용은 다음과 같습니다. 


- HQL 사용방법

-> 테이블의 모든 데이터 조회하기

-> 프로퍼티와 일부분 선택하기

-> HQL을 이용해 정렬 하기

-> HQL을 이용해 통계 정보 가져오기

- 네이티브 SQL 이용하기

  


HQL 사용방법


HQL을 사용할 때 반드시 데이터를 다룰 클래스를 지정합니다. Track 인스턴스의 리스트를 가져오는 최소한의 쿼리의 예시는 다음과 같습니다.


from Track

또는 

from com.oreilly.hh.data.Track


위와 같이 하이버네이트는 매핑한 클래스의 이름을 자동으로 임포트 합니다. 하지만 하나 이상의 클래스에서 동일한 이름을 사용한다면 패키지명까지 기입해서 사용합니다. 주위할 점은 위 Track은 테이블명을 지칭하는 것이 아닌 클래스이다. 


만약 동일한 이름을 가진 하나 이상의 매핑 클래스가 있습니다면 다음 방법을 이용합니다. 

  - 인스터스 이름 명시할때 전체 패키지명을 기입한다.

  - 매핑 문서에 import 태그를 사용해 한 쪽 또는 양 쪽 클래스를 대체하는 이름을 선언해야 한다.

  - 매핑 문서의 hibernate-mapping 태그 속성에 auto-impot="false"를 추가해 자동 import 기능을 중지시킨다.

  


HQL의 특징 


from 절에 인스턴스명을 넣는 방법과 유사하게, 자바의 다형성을 HQL에서 이용할 수 있습니다. 만약 다음과 같이 HQL을 작성하면 데이터베이스의 모든 객체를 가져올 수 있습니다. 


from java.lang.Object


Object는 모든 자바 객체의 부모이기 때문에, 이를 기본적으로 상속받는 모든 객체가 검색 대상이 됩니다. 인스턴스를 확장한 클래스의 부모 클래스 혹은 인터페이스로 지정하면 해당 객체를 상속/구현한 객체가 검색 대상이 됩니다. 이러한 기능은 포괄적으로 데이터를 다룰때 유용합니다. 하지만 제약이 있는데, 전체 결과에 대해 order by  절을 사용할 수 없고, 결과에 대해 Query이너페이스의 scroll() 메소드를 사용할 수 없습니다. 

 


프로퍼티 일부분만 선택해 사용하기 


기존의 HQL은 Select 절이 없고, From절만 사용해 객체 전체를 반환하는 방법만 사용했습니다. 그런데 리포트를 만들때 사용하게 된다면 특정 값만 필요할 때도 있습니다. HQL에서는 SQL의 Select 절과 같은 방법으로 프로퍼티 일부분만 가져 올 수 있습니다.  


만약 playtime이 지정한 조건보다 작은 Track의 제목만 가져오고 싶을 때 다음과 같이 작성할 수 있습니다.


select track.title

from com.oreilly.hh.track as track

where track.playTime <= :length


그리고 코드에서는 해당 쿼리가 반환하는 값은 String의 List를 반환합니다. 여기서 하나 이상의 속성 값을 가져오고 싶을 때는 어떻게 해야 할까요? 이것 또한 기존의 SQL처럼 속성값을 넣어서 작성할 수 있습니다.


select track.id, track.title 

from com.oreilly.hh.track as track

where track.playTime <= :length


위와 같이 쉼표(,)로 구분해서 프로퍼티를 나열하는 것입니다. 위 쿼리가 반환하는 값은 각 결과 값은 Object 배열을 포함하는 값입니다. 다음 코드를 보면서 어떻게 접근하는지 확인합니다. 


List titles = tracksNoLongerThan(Time.valueOf("00:05:00"), session);

for (ListIterator iter = titles.listIterator(); iter.hasNext;) {

  Object[] row = (Object[])iter.next();

  Integer id = (Integer)row[0];

  String title = (String)row[1];

  System.out.println("Track: " + title + " [ID=" + id + "]");

}


이러한 기능을 사용하는 이유는 여러 값을 다른 매핑 클래스에서 골라 가져올때 유용하게 사용할 수 있습니다. 이때 모든 객체를 가져오는 방식보다 성능에 대한 이점을 기대할 수 있다. 


반환하는 값을 특정 객체를 지정할 수 있습니다.. 만약 TrackSummary 클래스의 생성자가 id와 title 프로퍼티를 받도록 한다면 다음과 같이 쓸 수 있습니다. 


select new TrackSummary(track.id, track.title)



정렬 방법


HQL을 작성하는 법을 보면, 기존 SQL과 비슷한 문법을 확인할 수 있습니다. 정렬도 SQL과 비슷한 방법으로 order by 절을 추가해 정렬 기능을 추가할 수 있다. 다음은 샘플 코드입니다.


select track.id, track.title 

from com.oreilly.hh.track as track

where track.playTime <= :length

order by track.title desc



통계 함수 값 다루기 


리포트 관련 정보를 다루다 보면, 데이터의 개수, 평균 등의 통계값이 필요할 때가 있다. HQL에도 SQL처럼 집합 함수 기능이 있습니다. count(), min(), max() 와 같이 동일한 함수명을 이용해 집합 함수 기능을 사용할 수 있습니다.


select count(*), min(track.playTime), max(track.playTime)

from Track as track


위 결과 값은 하나의 결과만 나타나기 때문여 Query인터페이스의 uniqueResult()라는 메소드를 이용하 한 개의 열만 반환하는 메소드를 사용할 수 있습니다. 결과 값은 일부분 속성값을 가져오는 것과 같이 Object배열이 됩니다.




네이티브 SQL 쿼리를 이용하기


특정 SQL Dialect만 지원하는 HQL을 작성한다면, 데이터베이스 변경을 매우 어렵게합니다. 또는 기존 JDBC 기반의 프로젝트를 하이버네이트로 이관할 때 최소한의 작업만 하고 싶을 경우, 기존의 SQL을 재활용하고 싶을때 기존 SQL을 하이버네이트에서 사용할 수 있는 방법을 제공합니다. 


네이티브 SQL 쿼리를 사용하기 위해서는 다음 방법을 사용합니다. 

  1) 매핑 클래스내에 query 태그 대신 sql-query 태그를 사용합니다.

  2) sql-query 태그 내에 반환하려는 매핑 클래스와 클래스를 쿼리 내에서 참조 할 수 있는 별칭을 지정해야 합니다. 쿼리 내에 별칭(alias)는 모두 중괄호({})로 감싸야만 합니다. 

  

다음은 네이티브 SQL을 작성한 예입니다. 


<sql-query name="com.oreilly.hh.tracksEndingAt">

  <return alias="track" class="com.oreilly.hh.data.Track"/>

  <![CDATA[

       select {track.*}

      from TRACK as {track}

      where SECOND({track}.PLAYTIME) = :seconds

    ]]>

</sql-query>

  

네임드 파라미터의 경우 기존의 HQL에서 처럼 중괄호를 사용하지 않고 똑같이 사용할 수 있습니다.


Posted by 빌리 :

** 본 요약은 한빛미디어 '하이버네이트 프로그래밍' 책을 기준으로 작성되어져 있다.

** 본 설명은 바로 따라하기 하기엔 어려움이 있다. 책을 보지 않은 사람에게는 간단히 어떤 기능을 제공하는지 이해하는데 목적을 둔다.

** 하이버네이트 3.2.5.ga 버전, Ant 빌드를 기본적으로 사용한다.


7장 설정 파일 대신 어노테이션 사용하기

이전 장에서는 XML 매핑 문서를 기준으로 책의 내용을 진행해왔습니다. 이번 장에서는 자바 어노테이션을 이용해 어떻게 매핑 문서를 대체하는지 설명합니다.


하이버 네이트의 철학 : 오래된 어떤 자바 객체라도 어떤 방법으로든 영속화 한다.


자바의 어노테이션(Annotation) 


자바에서 보통의 클래스나 필드, 혹은 메소드에 부가적인 정보를 추가하는 문법이다. JAVA 5 버전부터 정식으로 지원하게 되었으며, 이전에는 JavaDoc의 형태를 이용해 작성하여 사용하였었다. JavaDoc는 프로그래머가 소스 코드에서 개별 파일로 분리해 별도로 관리하지 않으면서도 클래스나 API등의 수준 높은 만드는데 사용하는 방법이다. JavaDoc를 기존 목적 이외의 기능에 사용하려고 하였으며, 이를 활용해 XDoclet 프로젝트를 만들었습니다. 물론 하이버네이트에서는 이 프로젝트를 이용해 하이버네이트 XDoclet 태그도 개발되었습니다.

 


하이버네이트 어노테이션


어노테이션을 사용한 방법은 객체와 매핑 명세 정보를 한 파일에서 관리할 수 있도록 해, 파일을 읽는 사람은 무슨 일을 처리하는 내용인지 좀 더 쉽게 이해 할 수 있습니다. 또한 프로그래머는 설정에 필요한 작업량을 줄일 수 있는 장점이 있습니다.


하지만 객체 모델을 다양한 데이터베이스에 맞춰 변경해야 한다면 어노테이션 사용법은 적합하지가 않습니다. 이럴 경우에는 여러 개의 분리된 매핑 파일 세트를 만들어 사용하는 것이 더 적합합니다. 


그러면 하이버네이트 어노테이션을 사용하기 위해 다음과 같은 작업이 필요합니다. 


1. Hibernate annotations 라이브러리 다운로드 (3.2.5.ga 버전 기준)

-> 3.5 버전부터는 Hibernate core로 통합됨

2. annotation을 이용한 자바 객체 생성하기 

3. hibernate.cfg.xml 파일내 맵핑 파일 대신 맵핑 클래스 추가하기

-> JPA 인터페이스에 의존하는 스타일로 완전히 전환하면 맵핑 클래스 추가 없이 하이버네이트에서 자동으로 클래스를 찾아 낼 수 있다.(하이버네이트 세션 대신 JPA EntityManager의 하이버네이트 구현을 사용해야 한다)

4. 스키마 생성시 <annotationconfiguration> 태그 사용하기

-> Hibernate tool을 이용해 스키마 생성시 자바 객체 클래스들은 미리 컴파일 되어 있어야만 한다.

5. 하이버네이트 이용을 위해 config 정보를 읽는 클래스를 Configuration 대신 AnnotatoinConfiguration 클래스로 변경하기


어노테이션을 이용한 자바 객체 작성 방법


다음 소스를 보면서 자바 객체 작성법을 import 부분, class 부분, 그리고 attribute(속성) 부분으로 나눠 설명 드리겠습니다. 


import 부분을 보시면, 어노테이션도 일종의 클래스로 분리 되기 때문에 사용하고자 하는 어노테이션을 import에 명시해야 사용할 수 있습니다. 기본적으로 JPA API를 지원하기 때문에 공통적으로 사용할 수 있는 어노테이션의 경우 javax.persistence 패키지에 선언된 어노테이션을 가져옵니다. 그리고 하이버네이트 특유의 어노테이션 지원을 위해 org.hibernate.annotations 패키지에서 필요한 패키지를 가져옵니다. 


class 부분은 Entity 어노테이션으로 시작합니다. 이 것은 클래스가 영속화가 가능하다는 것을 표시합니다. Table 어노테이션은 필수 사항이 아닙니다. 하이버네이트에서는 table 어노테이션을 사용하지 않으면, 자동적으로 클래스 이름을 테이블명으로 지정해 사용합니다. 하지만, Table 어노테이션을 이용하 테이블명을 직접 지정할 수 있습니다. NamedQueries는 기존의 맵핑 문서를 작성하면서 보았던 사용자 지정 쿼리입니다. 이 부분은 하이버네이트에서 어노테이션을 사용할 때 나타나는 단점 중 하나로, 네임드 쿼리를 다른 파일로 분리해 둘 곳이 없기 때문에 발생하는 문제 입니다. 이 문제는 JPA EntityManager를 사용하면 네임트 쿼리를 xml파일로 내보내 해결할 수 있습니다. 


attribute 부분에서는 컬럼의 속성들을 Id, Column, Index, ManyToOne, JoinColumn 어노테이션을 이용해 기존 맵핑 문서에서 정의한 내용들을 손쉽게 작성하고 있는 것을 확인 할 수 있습니다. Column 어노테이션의 name 값을 설정해 Table 내의 컬럼명을 지정할 수 있습니다. 이 값을 지정하지 않으면, 하이버네이트에서는 자동으로 속성명을 컬럼명으로 사용하게 됩니다.



import java.util.HashSet;

import java.util.Set;


import javax.persistence.*;


import org.hibernate.annotations.Index;


@Entity

@Table(name="ARTIST")

@NamedQueries({

    @NamedQuery(name="com.oreilly.hh.artistByName", 

        query="from Artist as artist where upper(artist.name) = upper(:name)")

})

public class Artist {


    @Id

    @Column(name="ARTIST_ID")

    @GeneratedValue(strategy=GenerationType.AUTO)

    private Integer id;

    

    @Column(name="NAME",nullable=false,unique=true)

    @Index(name="ARTIST_NAME",columnNames={"NAME"})

    private String name;


    @ManyToMany

    @JoinTable(name="TRACK_ARTISTS", 

               joinColumns={@JoinColumn(name="TRACK_ID")},

               inverseJoinColumns={@JoinColumn(name="ARTIST_ID")})

    private Set<Track> tracks;


    @ManyToOne

    @JoinColumn(name="actualArtist")

    private Artist actualArtist;


    public Artist() {}


    public Artist(String name, Set<Track> tracks, Artist actualArtist) {

        this.name = name;

        this.tracks = tracks;

        this.actualArtist = actualArtist;

    }


    public Integer getId() {

        return id;

    }


    public void setId(Integer id) {

        this.id = id;

    }


    public String getName() {

        return name;

    }


    public void setName(String name) {

        this.name = name;

    }


    public Artist getActualArtist() {

        return actualArtist;

    }


    public void setActualArtist(Artist actualArtist) {

        this.actualArtist = actualArtist;

    }


    public Set<Track> getTracks() {

        return tracks;

    }


    public void setTracks(Set<Track> tracks) {

        this.tracks = tracks;

    }


    public String toString() {

        StringBuilder builder = new StringBuilder();


        builder.append(getClass().getName()).append("@");

        builder.append(Integer.toHexString(hashCode())).append(" [");

        builder.append("name").append("='").append(getName()).append("' ");

        builder.append("actualArtist").append("='").append(getActualArtist());

        builder.append("' ").append("]");

      

        return builder.toString();

    }

}


다른 객체의 경우도 위와 같은 방법을 이용해 어노테이션을 사용한 자바 객체로 변경할 수 있습니다. 그럼 6장에 나오는 복합 유저 타입 클래스는 어떻게 어노테이션을 지정해야 할까요? 그것은 @Embedded 어노테이션을 복합 유저 타입 클래스에 명시해 주면 됩니다. 



Posted by 빌리 :

** 본 요약은 한빛미디어 '하이버네이트 프로그래밍' 책을 기준으로 작성되어져 있다.

** 본 설명은 바로 따라하기 하기엔 어려움이 있다. 책을 보지 않은 사람에게는 간단히 어떤 기능을 제공하는지 이해하는데 목적을 둔다.

** 하이버네이트 3.2.5.ga 버전, Ant 빌드를 기본적으로 사용한다.


5장 다양한 연관

이번 장에서는 5개의 주제를 가지고 설명한다. 앞장에서 다룬 연관을 조금 더 세밀하게 설정하는 방법을 배운다. 간단히 요약하면 다음과 같다. 

  1) 연관의 초기화 형태 : 느슨한(Lazy), 열성적인(Eager) 

  2) 순서가 있는 컬렉션 사용하기

  3) 순서가 있는 컬렉션 설정 보강하기

  4) 순서있는 연관 컬랙션 삭제에 따른 자동처리

  5) 재귀 연관

  

연관의 초기화 형태 : 느슨한(Lazy), 열성적인(Eager) 


객체내에 다른 객체를 참조하는 값을 가질 수 있는데, 참조되는 객체를 처음 생성때부터 초기화 할것인지(eager), 아니면 사용되기 전까지 초기화를 미룰 것인지(lazy) 설정하는 방법을 설명한다.


하이버네이트3부터는 연관 객체에 대한 생성은 늦은 초기화가 기본적으로 사용된다. 즉, 실제로 데이터를 사용하기 전까지 데이터베이스에서 로드하지 않는다는 것이다. 그러나 주의할 것은 하이버네이트 세션을 닫게 되면 연관 객체의 늦은 초기화가 작동하지 않아 LazyInitializationException을 던진다. 즉, Lazy를 사용하려면 하이버네이트 세션을 닫으면 안된다는 것이다. 


그러면 기본적인 늦은 초기화를 사용하지 않으려면 어떻게 하는지 알아보면 다음 코드 처럼 작성하면 된다.


<set name="association_Obj" table="AAA_BBB" lazy="false">

  <key column="AAA_ID"/>

  <many-to-many class="com.billy.sample.BBB" column="BBB_ID"/>

</set>


위와 같이 lazy="false"를 추가해 빠른(eagerly) 초기화를 설정할 수 있다.


다양한 연관에서 위와 같이 늦은 초기화를 사용안하게 할 수 있지만 특정 클래스 참조의 대한 부분 모두를 빠른 초기화 설정을 하는 방법은 매핑문서의 class 태그에 lazy="false"를 직접 사용하면 된다.



순서가 있는 컬렉션 설정 방법


만약 다른 연관된 테이블 데이터에 순서가 있을때, 순서를 지정하기 위한 방법을 다룬다. 일단 List 컬랙션과 맵핑해야 하고, 리스트의 순서를 설정하는 list_index 태그를 추가해야 한다. 그리고 순서 조정 값을 갖는 컬럼을 데이터 베이스에 추가해야 한다. 코드를 보면 다음과 같다.


<list name="bbbList" table="AAA_BBB" lazy="false">

  <key column="AAA_ID"/>

  <list-index column="LIST_POS"/>

  <many-to-many class="com.billy.sample.BBB" column="BBB_ID"/>

</list>


하이버네이트에서는 LIST_POS를 관리하여 나중에 데이터베이스에서 꺼낸 리스트 내용으 우리가 저장한 컬럼과 동일한 순서로 나오게 된다. 


순서가 있는 컬렉션 설정 보강하기


* 데이터베이스 스키마에 테이블을 넣는 방법

1) 테이블의 컬럼에 자바 객체의 매핑 프로퍼티를 명시하는 것

2) 컬렉션(컬렉션의 값 또는 연관)을 정의하고, 그 컬렉션을 관리하는데 사용할 테이블과 컬럼을 지정하는 것


* 엔티티와 컴포넌트

- 엔티티 : 다른 객체에 대해 독립적으로 생성, 질의, 삭제될 수 있는 것

- 컴포넌트 : 다른 엔티티의 종속적인 부분으로서 데이터베이스에 저장되거나 데이터베이스에서 검색 될 수 있는 것


* 컴포넌트 맵핑

<list name="tracks" table="ALBUM_TRACK">

  <meata attribute="use-in-tostring">true</meta>

  <key column="ALBUM_ID"/>

  <index column="LIST_POS"/>

  <composite-element class="com.oreilly.hh.data.AlbumTrack">

    <many-to-one class="com.oreilly.hh.data.Track" name="track" cascade="all">

      <meta attribute="use-in-tostring">true</meta>

      <column name="TRACK_ID" />

    </many-to-one>

    <property name="disc" type="integer" />

    <property name="positionOnDisc" type="integer" />

  </composite-element>

</list>


위 컴포넌트 맵핑은 새로운 AlbumTrack라는 클래스를 소개한다. 3장에서 소개한 N:N 맵핑의 경우 조인 테이블을 사용한다고 했는데, 그 조인 테이블을 사용하는 클래스가 없다고 설명했다. 그런데 이와 같이 N:N 조인테이블에 부가정보를 추가해 새로운 관리 클래스를 생성할 수 있다. 이렇게 생성된 코드를 살펴보면 다음과 같다.


public class AlbumTrack  implements java.io.Serializable {

  private Track track;

  private Integer disc;

  private Integer positionOnDisc;


  public AlbumTrack() {

  }


  public AlbumTrack(Track track, Integer disc, Integer positionOnDisc) {

    this.track = track;

    this.disc = disc;

    this.positionOnDisc = positionOnDisc;

  }

 

  public Track getTrack() {

    return this.track;

  }

  

  public void setTrack(Track track) {

    this.track = track;

  }

  public Integer getDisc() {

    return this.disc;

  }

  

  public void setDisc(Integer disc) {

    this.disc = disc;

  }

  public Integer getPositionOnDisc() {

    return this.positionOnDisc;

  }

  

  public void setPositionOnDisc(Integer positionOnDisc) {

    this.positionOnDisc = positionOnDisc;

  }


  /**

   * toString

   * @return String

   */

  public String toString() {

 StringBuffer buffer = new StringBuffer();


    buffer.append(getClass().getName()).append("@").append(Integer.toHexString(hashCode())).append(" [");

    buffer.append("track").append("='").append(getTrack()).append("' ");

    buffer.append("]");

     

    return buffer.toString();

  }

}


위 코드는 id 프로퍼티가 빠져있다. 컴퍼넌트 클래스는 식별 필드나 특별한 인터페이스 구현이 필요 없다. 


순서있는 연관 컬랙션 삭제에 따른 자동처리


- 부모 객체와 자식 객체의 종속성 설정 : 하이버네이트에서는 "부모"객체가 실행되면 "자식" 혹은 "의존" 객체까지 전이되는 연산을 cascade 어트리뷰트로 처리할 수 있다. 이 기능은 모든 종류의 컬렉션과 연관에 적용된다. 

- 사용 방법 : 객체 맵핑 프로퍼티에 <cascade> 태그를 추가한다.

  -> cascade 값 : none, save-update, delete, all(save-update+delete)

  -> 전체 default cascade 변경 : <hibernate-mapping> 태그에 default-cascade 어트리뷰트 추가

  -> 부모가 삭제되면 자식도 동시에 삭제 가능하도록 설정 가능

  -> 중간에 order관련 값들을 자동으로 변경해줌

  

재귀 연관


객체나 테이블에서 자체적으로 연관을 맺을 수 있다. 트리같은 객체 구조를 생성할 수 있다는 것이다. 이는 단순하다. 

Artist 클래스 맵핑 문서야 다음과 같이 자기 자신을 참조하는 필드를 추가하면 된다. 


<many-to-one name="actualArtist" class="com.oreilly.hh.data.Artist">

 <meta attribute="use-in-tostring">true</meta>

</many-to-one>


  

  

  

Posted by 빌리 :

** 본 요약은 한빛미디어 '하이버네이트 프로그래밍' 책을 기준으로 작성되어져 있다.

** 본 설명은 바로 따라하기 하기엔 어려움이 있다. 책을 보지 않은 사람에게는 간단히 어떤 기능을 제공하는지 이해하는데 목적을 둔다.

** 하이버네이트 3.2.5.ga 버전, Ant 빌드를 기본적으로 사용한다.


4장 컬렉션과 연관

본 장에서는 객체간 관계나 그룹이 처리되는 방법은 알아본다.


테이블 간의 관계 표현하기


두개의 클래스 용 맵핑 문서를 만들고, 그 안에 'set'이라는 태그를 이용해 연결 정보를 추가하여 사용한다.


N:N 연결 관계는 다음 코드를 연결할 양쪽 클래스 맵핑 문서에 다음 내용을 추가해 구현한다.


<set name="[필드명]" table="[조인 테이블명]">

  <key column="[현재 테이블의 아이디 키]"/>

  <many-to-many class="[연결되는 대상 클래스]" column="[연결되는 테이블의 아이디 키]"/>

</set>


양쪽에 <many-to-many> 태그를 사용하면, 하이버네이트에서는 자동으로 현재 테이블의 아이디 키와 연결되는 테이블의 아이디 키가 컬럼을 가진 조인 테이블을 생성한다. 이 테이블과 실제로 맵핑되는 객체는 존재하지 않고 N:N 관계를 유지하기 위한 테이블인 조인 테이블로 사용하게 된다.


실제 전체 코드를 보면 다음과 같이 작성될 수 있다.


AAA 클래스용 매핑 문서

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

<class name="com.billy.sample.data.AAA" table="AAA">

<meta attribute="class-description">

A 샘플 클래스 매핑 예제

</meta>

<id name="id" type="int" column="AAA_ID">

<meta attribute="scope-set">protected</meta>

<generator class="native"/>

</id>

    

<property name="name_a" type="string" not-null="true"/>

    

    <set name="bset" table="AAA_BBB" inverse="true">

      <meta attribute="field-description">연관된 B 클래스</meta>

      <key column="AAA_ID"/>

      <many-to-many class="com.billy.sample.data.BBB" column="BBB_ID"/>

    </set>

  </class>

</hibernate-mapping>


BBB 클래스용 매핑 문서

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

<class name="com.billy.sample.data.BBB" table="BBB">

<meta attribute="class-description">

B 샘플 클래스 매핑 예제

</meta>

<id name="id" type="int" column="BBB_ID">

<meta attribute="scope-set">protected</meta>

<generator class="native"/>

</id>

    

<property name="name_b" type="string" not-null="true"/>

    

    <set name="aset" table="AAA_BBB">

      <meta attribute="field-description">연관된 A 클래스</meta>

      <key column="BBB_ID"/>

      <many-to-many class="com.billy.sample.data.AAA" column="AAA_ID"/>

    </set>

  </class>

</hibernate-mapping>


위 코드 중에 AAA 클래스용 매핑 문서의 <set> 태그 안에 inverse(역매핑)이 설정 되어 있다. 이는 AAA클래스의 bset이 변경이 일어나면 AAA_BBB 테이블이 변경되지 않지만, BBB클래스의 aset이 변경이 일어났을때 AAA_BBB 테이블이 자동 갱신되도록 설정한다.


이렇게 맵핑 문서를 작성하고 난 후 Hibernate tool을 이용해 소스코드를 생성하면 해당 객체에 다음과 같은 코드가 추가 된다.


public class AAA implements java.io.Serializable {

  ...

  private Set bset = new HashSet(0);

  

  public Set getBset() {

    return this.bset;

  }

  

  public void setBset(Set bset) {

    this.bset = bset;

  }

  ...

}


그런데 위의 코드는 Java 5 버전에서는 Typesefe 경고가 발생한다. 이를 처리하기 위해서는 자바 코드 생성시 다음과 같은 코드를 추가해준다.(Ant task기준)


<hbm2java jdk5="true">

위 코드를 추가 후에 자바코드를 추가 하면 


private Set<BBB> bset = new HashSet<BBB>(0); 

과 같이 타입이 명시된 제너릭 코드가 생성된다.


 

객체에서 관계된 테이블(컬렉션) 데이터 입력하고, 데이터 읽어오기


위 단계에서 N:N 설정된 데이터를 사용하는 방법은 간단한다. 자동생성된 클래스의 Set 부분에 해당 값을 추가 해서 저장하면 자동으로 조인테이블에 데이터가 생성된다. 데이터 읽어오는 방법도 기존의 앞에서 해당 객체를 불러오는 방법과 동일하게 사용하면 데이터를 가져올 수 있다.



1:N 관계 표현하기


N:N 관계 설정하는 방법과 비슷하지만 조금 더 간단한다. N:N에서 설정한 맵핑 파일에 주석을 단다고 가정하면 다음과 같이 맵핑 코드를 작성할 수 있다.


<set name="comments" table="AAA_COMMENTS">

  <key column="AAA_ID"/>

  <element column="COMMENT" type="string"/>

</set>


그러면 AAA_COMMENTS 테이블이 생성되고, 자바 코드상에도 Set<String> comments가 추가되어 사용할 수 있게 된다.



Posted by 빌리 :

Hibernate 책 학습

1장 

기본 환경 설정

  - Ant를 이용한 환경 설정

  - Maven-ant task를 이용한 라이브러리 자동 다운로드 

  

2장

1) 자바 클래스와 DB 테이블 사이의 맵핑 문서 작성하기

2) 맵핑 코드를 이용해 자바 객체 클래스 생성 방법

3) 맵핑 코드를 이용해 DB 테이블 스키마 생성 방법

  - hibernate.properties 파일을 이용한 기본 DB접속 설정

  

+ hibernate를 properties 파일을 이용해 설정하는 방법

+ log4j를 properties 파일을 이용해 설정하는 방법

-> 기본적으로 해당 프로그램들이 properties 파일을 클래스패스의 최상의 디렉토리를 검색하기 때문에 클래스패스 최상위에 파일을 넣는다.


+ Ant를 이용한 자바 빌드 방법

+ Ant를 이용한 파일 복사 방법


3장

1) 기본 설정을 hibernate.properties 대신 hibernate.cfg.xml 파일로 대체

  - hibernate.cfg.xml 파일 생성

  - 기존 ant build.xml 파일에 해당 xml 파일 참조하도록 수정

  

2) 자바 객체를 데이터베이스 레코드로 저장하기

3) 데이터베이스 레코드를 자바 객체로 가져오기(1)

  - HQL(하이버네이트의 sQL기반 쿼리언어)를 이용한 데이터베이스 조회

  

4) 데이터베이스 레코드를 자바 객체로 가져오기(2)

  - 네임드 쿼리/네임드 파라미터

  - 자바 소스에서 쿼리 분리 하기(맵핑 XML 파일에 넣기)


4장
1) 테이블 간의 조인 관계를 표현하기 (다 대 다 관계) - 컬렉션(Collection)
  * 다대다 조인 테이블을 하이버네이트에서 자동으로 생성관리함
  * 다른 테이블 데이터는 객체 내에 컬랙션으로 표현되어 추가됨
  - Column에 대한 상세 설정 방법
    -> Index 설정, not null 설정, toString 메소드 설정
    
  - 자바5의 타입세이프티 설정 방법
  
2) 객체에서 컬랙션 데이터 입력하기(연관 테이블에 데이터 입력)
3) 객체에서 컬랙션 데이터 읽어오기(연관 테이블에 데이터 검색)
4) 다대다 관계에 대한 양방향 맵핑 기능 이용(이론)
5) 단순한 조인 관계 표현하기(1 대 다 관계) 
  

5장
1) 느슨한 연관
  - 객체를 실제로 참조하기 전까지 연관된 객체를 로드하지 않는 방식 지원
    -> 하이버네이트 세션이 열려져 있는 상태에서만 작동
2) 순서가 있는 컬렉션 설정 방법

3) 다시 읽어보기!!!

4) 순서있는 연관 컬랙션 삭제에 따른 자동처리
  - 부모 객체와 자식 객체의 종속성 설정
    -> 부모가 삭제되면 자식도 동시에 삭제 가능하도록 설정 가능
    -> 중간에 order관련 값들을 자동으로 변경해줌
  
5) 재귀 연관
  - 트리와 같은 구성
  

6장 사용자 정의 값 맵핑 시키기
: 객체의 하나의 값(property)이 enum 또는 특정 클래스랑 직접 맵핑되어 사용되어 질때
즉 컬럼 하나의 값 또는 두개 이상의 값이 enum 또는 클래스와 맵핑 될 수 있는 방법을 알아본다.

1) 컬럼 값 하나를 enum값과 맵핑 시키기 - UserType
2) 테이블의 여러 컬럼을 클래스와 맵핑 시키기 - 복합사용자타입(CompositeUserType)

- 사용자 정의 값 맵핑은 다음 단계로 개발된다.
  .1-enum 값 또는 클래스 정의하기
  .2-(단일 타입)org.hibernate.usertype.UserType 인터페이스를 구현하는 클래스 작성하기
     (복합 타입)org.hibernate.usertype.CompositeUserType 인터페이스를 구현하는 클래스 작성하기
    -> 구현 클래스는 enum 또는 클래스를 Hibernate에서 어떻게 다룰지 구현
  .3-Class 맵핑 문서(ex:Track.hbm.xml)에 프로퍼티 추가하기
  .4-사용자 정의 클래스 컴파일 하기
  .5-Hibernate Tool을 이용해 코드 생성하기
  .6-모든 소스 컴파일 하기
  .7-Hibernate Tool을 이용해 Schema 생성하기
  
  ** Hibernate Tool이 사용자 정의 클래스를 인식하기 위해선 먼저 사용자 정의 클래스가 컴파일 되어 있어야만 한다.


7장 설정 파일 대신 어노테이션(annotation)을 이용해 설정하기
: 이 경우에는 이전에 만들어 놓았던 legacy 코드가 있을때 이를 어떻게 설정파일 없이
하이버네이트를 적용하는지에 대해 설명 한다. 

- 어노테이션을 이용한 하이버네이트 적용 방법
  .1- annotation 관련 하이버네이트 라이브러리를 얻어온다.
  .2- configuration이 어노테이션을 사용한다고 명시한다.
    -> ant라면 <hibernatetool> 하위에 <configuration> 대신 <annotationconfiguration> 태그를 이용해 config 파일을 지정한다.
  .3- 컴파일 순서를 다음으로 진행 되도록 변경 한다. (스키마를 생성하기 전에 전체 클래스들이 컴파일 되어 있어야 하이버네이트가 클래스를 인식한다.)
      클래스 파일 경로에 xml등 설정 파일 복사 -> 소스코드 컴파일 -> 스키마 생성작업
  .4- hibernate.cfg.xml에 맵핑할 클랙스 목록을 추가한다.
  .5- 맵핑한 클래스에 어노테이션을 추가한다.
  .6- 스키마 생성
  .7- 실행 프로그램에서 config 정보를 읽어오는 클래스를 AnnotationConfiguration 클래스를 사용하도록 변경


8장 크리테리아(Criteria) 쿼리 
: Where 절을 객체의 메소드 호출로 대체 하자. 기존 외부 XML 파일에 쿼리를 빼 놓으면, 쿼리가 실행 되기 전까지 쿼리의 오류를 확인할 수 없는 문제가 발생한다. 이를 해결하기 위해 코드상에 Where 조건을 만들 수 있는 기능을 추가해놓았다. 

- 기본 크리테리아 사용 방법 
  -> 기본 조회
  -> 정렬 
  -> 기본 사용 방법
    .1- Session 에서 createCriteria()를 이용해 criteria 객체 생성
    .2- criteria 객체에 조건 추가
    .3- criteria의 list() 호출

- And / Or 조건 추가하기
  -> OR : Restrictions.disjunction()에 생성되는 객체에 조건 추가
  
- 테이블의 특정 컬럼 값만 얻기
  -> 하나의 컬럼 조회 : hibernate는 String 리스트를 리턴
  -> 여러 컬럼 조회 : 각 컬럼의 타입에 맡는 Object배열 리스트를 리턴
  
- 테이블의 통계 정보 얻기

- 연관 테이블의 조건 걸기
  .1- Session 에서 createCriteria()를 이용해 criteria 객체 생성
  .2- criteria 객체를 이용해 sub criteria 객체 생성하기(생성시 조건을 연결할 연관 클래스를 넘겨줘야됨)
  
- example객체를 이용해 Criteria 객체 생성하기
: criteria를 직접 생성하지 말고, 기존 vo객체를 이용해 검색 하고 싶을때 사용한다.
  .1- VO객체에 검색할 속성 값을 설정해 Example 객체를 생성하기
    ex) VOobj vo = new VOobj();
        vo.setProperty("test");
        Example example = new Example(vo);
  .2- 생성된 example 객체를 critera에 조건으로 추가하기
  
- Criteria 객체 사용할때 조건 추가하는 방법
  .1- Restrictions 팩토리 클래스 이용하기
    ex) criteria.add(Restrictions.le("property", value));
  .2- Property 클래스 이용하기
    ex) criteria.add(Property.forName("property").le(value));
    

9장 HQL 
- HQL 작성방법
- 테이블의 모든 데이터 조회하기
- 프로퍼티와 일부분 선택하기
- HQL을 이용해 정렬 하기
- HQL을 이용해 통계 정보 가져오기
- 네이티브 SQL 이용하기
  -> 기존 쿼리를 Hibernate로 마이그레이션 할때 사용하기 

Posted by 빌리 :