'inverse'에 해당되는 글 2건

  1. 2008.02.18 m-n 연관 매핑, inverse 속성 (2)
  2. 2008.02.17 1-n 연관 매핑(컬렉션 매핑), inverse 속성
참고 : 래퍼런스 6장

카테고리는 여러개의 아이템을 가질 수 있고 아이템은 여러개의 카테고리에 포함될 수 있습니다.
사용자 삽입 이미지









단방향 매핑

<bag /> 요소의 table 속성 값으로 다대다 관계를 해소하기 위한 조인 테이블을 지정 했습니다.
그리고 <many-to-many /> 요소를 이용해 연관된 테이블의 컬럼과 클래스를 매핑 합니다.
cascade에 delete 옵션이 없는 이유는 어떤 카테고리가 삭제될 때 연관된 아이템까지 삭제되므로 삭제 되는 아이템들을 포함하는 카테고리에 영향을 미치기 때문입니다.

양방향 매핑
Item쪽도 마찬가지로 <many-to-many /> 요소를 이용해 연관된 테이블의 컬럼과 클래스를 매핑 합니다.
다른 점은 컬렉션 요소(<bag />) 의 inverse 속성을 true로 설정한 것입니다. 양방향 매핑이므로 자바 객체상에서 양방향 링크가 되어 있어야 한다는건 이전에도 밝힌바 있습니다.

그렇다면 inverse 속성 무엇일까요?
이전 글(1-n 연관 매핑)의 중간 부분에 inverse 속성에 대해 정리한게 있습니다. inverse 속성은 1-n 관계뿐 아니라 m-n 관계에서도 같은 의미를 가집니다. 만약 위(양방향 매핑) 상황에서 inverse 속성을 제거하면 어떤 일이 벌어질까요? 아래 코드를 실행하면...
Category c = new Category("카테고리1");
c.addItem(new Item("아이템1"));
c.addItem(new Item("아이템2"));
c.addItem(new Item("아이템3"));
      
session.save(c);
addItem 메서드는 양방향 링크를 위한 관리메서드 입니다.
public void addItem(Item item) {
    item.getCategories().add(this);
    items.add(item);
}
이런 작업이 수행 됩니다.
......
insert into CATEGORY_ITEM (CATEGORY_ID, ITEM_ID) values (?, ?)
insert into CATEGORY_ITEM (CATEGORY_ID, ITEM_ID) values (?, ?)
insert into CATEGORY_ITEM (CATEGORY_ID, ITEM_ID) values (?, ?)
insert into CATEGORY_ITEM (ITEM_ID, CATEGORY_ID) values (?, ?)
insert into CATEGORY_ITEM (ITEM_ID, CATEGORY_ID) values (?, ?)
insert into CATEGORY_ITEM (ITEM_ID, CATEGORY_ID) values (?, ?)
3개의 insert는 Category에 대한 변경을 알아채고 수행한 것이고
나머지 3개의 insert는 Item에 대한 변경을 알아채고 수행한 것입니다. 이렇게 불필요한 나머지 3개의 수행을 방지하기 위해 주최측의 반대쪽에 inverse 속성을 설정하는 것입니다. 다시 한번 정리하자면 inverse 속성은 연관의 한 측을 끝으로 만들어 변경을 무시하도록 하는 속성 입니다.

한가지 의문점...
문득 이런 생각이 들었습니다.
"만약 자바 객체상에서 양방향 링크가 이루어지지 않는다면 inverse 속성도 필요 없지 않을까?"
그래서 자바 객체상에서 양방향 링크를 제거하고 inverse 속성도 제거 해봤습니다.
위에 나와 있는 양방향 링크와 동일한 테스트 입니다.
Category c = new Category("카테고리1");
c.addItem(new Item("아이템1"));
c.addItem(new Item("아이템2"));
c.addItem(new Item("아이템3"));
      
session.save(c);
addItem 메서드에서 더 이상 양방향 링크를 하지 않습니다.
public void addItem(Item item) {
    items.add(item);
}
실행 결과 입니다.
insert into CATEGORY_ITEM (CATEGORY_ID, ITEM_ID) values (?, ?)
insert into CATEGORY_ITEM (CATEGORY_ID, ITEM_ID) values (?, ?)
insert into CATEGORY_ITEM (CATEGORY_ID, ITEM_ID) values (?, ?)
결과는 이상이 없습니다. 1-n 연관에서는 양방향 링크가 없으면 부모를 참조하는 컬럼이 null로 되었지만 m-n 연관에서는 이상이 없었습니다. insert 이외에 카테고리를 가져온후 양방향 링크 상태가 되어있는지 테스트도 이상이 없고 delete 테스트도 이상이 없었습니다.
그래서 저는 이렇게 생각 합니다.
어플리케이션이 객체 저장 시점에서 양방향 링크가 되지 않아도 상관 없다면 inverse 속성이 없는게 이득이라고 생각 됩니다. 왜냐면 inverse 속성이 존재한다면 owner side 측과 other side(inverse) 측이 구분되어 owner side로만 작업을 해야 하는데 inverse 속성이 없다면 owner side, other side 구분이 없어지기 때문에 어느쪽이든 작업이 가능하기 때문 입니다. 또한 inverse가 없다고 해서 객체를 가져온 시점에 양방향 링크가 안되어 있진 않으니까 문제가 없다고 생각 됩니다.
신고

'Hibernate' 카테고리의 다른 글

객체의 상태  (0) 2008.03.02
상속 매핑  (0) 2008.02.23
m-n 연관 매핑, inverse 속성  (2) 2008.02.18
1-n 연관 매핑(컬렉션 매핑), inverse 속성  (0) 2008.02.17
n-1 연관 매핑  (0) 2008.02.17
1-1 연관 매핑  (0) 2008.02.13
Posted by 째코
참고 : 래퍼런스 6장

하나의 게시물은 여러개의 첨부파일을 가질 수 있으며 여러개의 덧글과 여러개의 태그를 가질 수 있습니다.
이 때 부모측에 자식을 컬렉션 타입으로 정의하게 되는데 Hibernate가 지원하는 컬렉션 타입에 대해 하나씩 알아보겠습니다. 이 글에서는 컬렉션 요소별로 모든 상황을 넣을 수 없는 관계로 어떤건 값 타입의 컬렉션이고 어떤건 엔티티 타입의 컬렉션인데 예제에 값 타입만 있다고 해서 값 타입만 할 수 있는건 아닙니다.

Set (초기 클래스 HashSet)
java.util.Set 타입은 <set /> 요소로 매핑 합니다.
Set 타입은 중복이 허용되지 않고 순서가 없다는 특징이 있습니다. 하지만 순서가 없다고 해서 정렬을 할 수 없는건 아닙니다. <set /> 요소의 order-by 속성을 이용하면 됩니다. 또한 Set 타입에 저장될 영속 객체들은 논리적인 중복을 체크하기 위해 equals, hashCode 메소드를 오버라이드 해야 합니다.
기본 데이터 타입을 가지는 컬렉션
Set 컬렉션에 반드시 엔티티 타입의 객체만 올 수 있는건 아닙니다.  기본 데이터 타입이든 컴포넌트 타입이든 엔티티 타입이든 상관 없습니다. 이번 예제는 기본 데이터 타입으로 해볼 것인데 기본 데이터 타입이기 때문에 type 속성을 명시해야 하는걸 주의해야 합니다.
사용자 삽입 이미지

테스트 코드 보기


List (초기 클래스 ArrayList)
java.util.List 타입은 <list /> 요소로 매핑 합니다.
List 타입은 중복이 허용되고 순서가 있다는 특징이 있으며 컬렉션에 들어올 객체들이 저장될 테이블에는 순서를 정하기 위한 별도의 컬럼이 필요합니다. 순서로 사용할 컬럼은 <list /> 요소의 하위 요소인 <list-index /> 요소를 이용해 매핑 합니다. <list-index /> 요소의 base 속성은 순서의 시작 값 입니다. 만약 5를 지정한다면 테이블에는 5부터 값이 들어 갑니다. 하지만 컬렉션의 인덱스는 여전히 0부터 시작 됩니다.
컴포넌트 타입을 가지는 컬렉션
이번 예제는 컴포넌트 타입으로 해보겠습니다. 컬렉션에 들어갈 컴포넌트 타입의 객체는 <composite-element /> 요소를 이용해 매핑 합니다. 예제에는 없지만 <parent /> 요소를 이용하면 부모를 참조할 수 있습니다.
사용자 삽입 이미지

테스트 보기


Bag(초기 클래스 ArrayList)
Bag 타입은 자바에서 지원되지 않는 타입이기 때문에 java.util.Collection 타입을 사용 하며 <bag />또는
<idbag /> 요소로 매핑 합니다. Bag 타입은 중복을 허용되고 순서가 없다는 특징이 있습니다.

<bag /> 요소를 이용한 매핑
기본 데이터 타입을 가지는 컬렉션
맨 처음 했던 Set 매핑의 예제를 그대로 이용 했습니다. <set /> 요소대신 <bag />요소를 사용한 것을 빼고는 바뀐게 없습니다. 작동상 차이점은 중복이 허용된다는 점 입니다. 테스트 코드는 생략 합니다.엔티티 타입을 가지는 컬렉션
사용자 삽입 이미지









먼저 단방향 예제를 보겠습니다. 엔티티 타입의 연관이기 때문에 cascade 속성을 all로 지정 했습니다.
all값은 delete-orphan을 제외한 모든 값 입니다.

테스트 보기


이제 위 예제를 양방향으로 매핑 해보겠습니다.
위 예제에서 Comment 매핑에 다음을 추가 합니다.
이번 예제는 아주 중요합니다. 아래 있는 테스트 코드를 반드시 참고해야 합니다.

테스트 보기

inverse 속성에 대해 한번더
바로 위에 글(양방향 매핑의 테스트 부분)을 읽어봤더니 쉽게 설명을 못한거 같아 다시 한번 정리해 봅니다.
inverse 속성에 대해서는 일단 무시 하고 자바 객체상에서 양방향 링크를 생각해 봅시다.
Article에서 Comment를 참조하고 있고 Comment에서도 Article을 참조하고 있습니다.
이 때 Article 객체를 저장시 Hibernate는 Article 객체의 변경뿐 아니라 Article 객체에서 참조하고 있는 Comment 객체의 변경까지 알아냅니다. 두개의 변경사항에 대한 작업으로 첫번째 Article에 추가된 Comment를 insert하고, 두번째 Comment가 참조하는 Article의 연관 컬럼을 update 합니다. 여기서 두번째 update는 불필요한 작업입니다. 이런 불필요한 작업을 하지 않기 위해 inverse를 설정하는 것 입니다. inverse가 설정되어 있는 쪽은 변경에 대한 작업을 하지 않습니다. inverse 속성은 1-n 연관에서 1측에 설정 합니다.

<idbag /> 요소를 이요한 매핑
값 타입은 예전 글에서 다뤘듯이 주키가 없다는 특징이 있습니다. 주키가 없으므로 부모에 대한 참조키와 나머지 모든 컬럼들을 비교하여 하나의 객체로 식별하게 됩니다. 컬럼이 많아질수록 그 만큼 속도도 떨어지기 마련 입니다. 하지만 <idbag />를 이용하면 주키를 사용할 수 있으므로 주키 하나로써 객체를 식별할 수 있습니다.
가장 위에 있는 <set /> 요소에 나와 있는 그림과 비교해 보세요.
사용자 삽입 이미지









<collection-id /> 요소로 주키를 매핑 합니다. 값 타입에 주키가 생김으로 해서 엔티티 타입이 되는건 아닙니다. <idbag /> 요소를 이용했을 때 주키는 Hibernate가 관리하며 사용자가 직접 컨트롤 할 수는 없습니다. 모양새가 엔티티 타입처럼 보이는 것일뿐 어디까지나 값 타입일 뿐 입니다. 이제 컬렉션에 있는 객체를 삭제할 때 주키를 이용하게 됨으로써 성능이 향상 될 것입니다. 한가지 주의 사항이 있는데 현재(3.2) <collection-id /> 요소에서 native 식별자 생성기는 지원되지 않습니다.

Map(초기 클래스 HashMap)

java.util.Map 타입은 <map /> 요소로 매핑 합니다.
Map 타입은 키가 중복될 수 없고 값은 중복이 가능하며 순서가 없다는 특징이 있습니다.
<map-key /> 요소로 Map 타입에서 사용하는 키를 설정 합니다. 간단하므로 테스트는 생략 하겠습니다.

SortedSet, SortedMap(초기 클래스 TreeSet, TreeMap)
위에서 살펴봤던 Set, Map 타입은 순서가 없습니다. SortedSet 타입과 SortedMap 타입을 사용하면 정렬을 할 수 있습니다. Sorted~ 라고 해서 별도의 매핑요소가 있는건 아니고 기존의 <set />, <map /> 요소를 그대로 이용하며 sort 속성을 설정합니다. sort 속성 값으로 unsorted, natural, java.util.Comparator 구현체가 될 수 있습니다. 다음 예제는 앞서 살펴봤던 예제에서 sort 속성만 추가한 것입니다.

sort 속성을 natural로 지정하면 오름차순으로 정렬하게 됩니다.
정렬방식을 변경하고자 한다면 Comparator 인터페이스를 구현해 지정하면 됩니다.

order-by 속성
sort 속성은 <set />, <map /> 요소에만 있으며 SortedSet, SortedMap 타입을 사용해야만 합니다.
그리고 데이터베이스로부터 객체를 가져온뒤 메모리상에서 정렬을 합니다. 반면 order-by 속성은 <list /> 를 제외한 모든 컬렉션 요소에 있으며 데이터베이스로부터 객체를 가져올때 정렬한 상태로 가져 옵니다. order-by 속성 값으로는 SQL의 일부분(정렬)을 지정합니다. order-by 속성을 사용할 경우 Set, Map 타입은 내부적으로 LinkedHashSet, LinkedHashMap 을 사용하므로 자바1.4 이상에서 사용해야 하고 Bag 타입의 경우는 내부적으로 ArrayList를 사용하므로 자바1.3 이상에서 사용해야 합니다.

신고

'Hibernate' 카테고리의 다른 글

상속 매핑  (0) 2008.02.23
m-n 연관 매핑, inverse 속성  (2) 2008.02.18
1-n 연관 매핑(컬렉션 매핑), inverse 속성  (0) 2008.02.17
n-1 연관 매핑  (0) 2008.02.17
1-1 연관 매핑  (0) 2008.02.13
Value 타입 매핑  (0) 2008.02.06
Posted by 째코