'하이버네이트'에 해당되는 글 21건

  1. 2008.04.20 HQL - update, delete 절
  2. 2008.04.17 HQL - 식별자 프로퍼티 참조
  3. 2008.04.16 HQL - 집계 함수, group by, having
  4. 2008.04.13 HQL - 컬렉션 필터
  5. 2008.04.13 HQL - fetch
update, delete 절에서 몇가지 규칙 입니다.
(update | delete) from EntityName (where where_conditions)
from 키워드는 옵션 입니다.
from 절 내에는 오직 한개의 엔티티만 올 수 있습니다.
alias 는 옵션이고 alias를 지정했다면 프로퍼티들은 alias를 통해 접근해야 합니다. alias가 있는데 alias를 사용하지 않으면 규칙에 어긋난다는 내용이 있지만 테스트 해보니 alias를 수식하지 않아도 상관 없었습니다.
join 구문들은(함축이든 명시적이든) 대량 HQL 질의 속에 지정될 수 없습니다.
단 서브 질의들은 where 절에서 사용될 수 있습니다.

모든 Seller 객체에 대하여 대량의 업데이트를 수행하고 적용된 객체의 갯수를 돌려 받습니다.

int updateResult = session.createQuery("update Seller s set s.name = :name")
                            .setString("name", "이름변경")
                            .executeUpdate();
버전 관리를 할 경우 update 쿼리만으로는 버전이 변경되지 않습니다.
따라서 버전을 갱신하고 싶다면 update versioned 절을 사용해야 합니다.

where 절에서 서브쿼리를 사용해 봤습니다.
int updateResult = session.createQuery("update Seller s set name = :name " +
                                                            "where s in (select s2.id " +                                                                                                    "from Seller s2 join s2.items i where i.price > 2000)")
                            .setString("name", "이름변경")
                            .executeUpdate();

수정을 했다고 해서 이미 로딩된 객체는 영향을 받지 않습니다.
이럴 땐 refresh() 메서드로 객체를 다시 가져와야 합니다.
Seller s = (Seller)session.get(Seller.class, 1);
update...
session.refresh(s);

가격이 2000 미달인 Item 객체에 대하여 대량의 삭제를 수행하고 삭제된 갯수를 돌려 받습니다.
int deleteResult = session.createQuery("delete Item i where i.price < :price")
                           .setInteger("price", 2000)
                           .executeUpdate();
신고

'Hibernate' 카테고리의 다른 글

HQL - update, delete 절  (0) 2008.04.20
HQL - 식별자 프로퍼티 참조  (0) 2008.04.17
HQL - 집계 함수, group by, having  (0) 2008.04.16
HQL - 컬렉션 필터  (0) 2008.04.13
HQL - fetch  (0) 2008.04.13
HQL - select 절  (0) 2008.04.13
Posted by 째코
래퍼런스 14.5장에 이렇게 나와 있습니다.

  • 엔티티가 id로 명명된 비-식별자 프로퍼티를 정의하지 않았다면 특별한 프로퍼티 id가 엔티티의 식별자 프로퍼티를 참조하는데 사용된다.
  • 만약 엔티티가 명명된 식별자 프로퍼티를 정의 했다면 그 프로퍼티를 식별자 프로퍼티로 사용할 수 있다.
  • 엔티티가 복합 식별자 프로퍼티를 사용할 경우
- id로 명명된 비-식별자 프로퍼티를 정의 했다면 명명된 식별자 프로퍼티로만 참조될 수 있다.
- 그 밖의 경우는 특별한 프로퍼티id가 식별자 프로퍼티를 참조하는데 사용될 수 있다.

복합키를 사용할 경우의 조건은 복합키를 사용하든 안하든 똑같이 적용되는 조건같은데 마치 복합키 사용시에만 적용되는 것처럼 써있네요. 잘 읽어보면 복합키를 사용하지 않을때 조건 2가지와 복합키를 사용할 때 조건 2가지가 같은 의미로 보이지 않나요?

다시 본론으로 돌아가서 위 조건들은 3.2.2 부터 변경 되었다는 멘트와 함께 변경된 이유에 대해서 나옵니다.
3.2.2 이전 버전에서 특별한 프로퍼티 id는 항상 식별자 프로퍼티를 참조 했는데 그로 인해 id로 명명된
비-식별자 프로퍼티들을 결코 참조할 수 없기 때문이다.


테스트
Seller의 식별자 프로퍼티를 id2로 설정하고 테스트 해봤습니다.
from Seller s where s.id > 5 and s.id2 > 5

실행되는 SQL
select
    seller0_.id2 as id1_0_,
    seller0_.name as name0_
from
    Seller seller0_
where
    seller0_.id2>5
    and seller0_.id2>5

이게 무슨일?? 3.2.2 이전 버전에서 id로 명명된 비-식별자 프로퍼티를 결코 참조할 수 없기 때문에 변경 했다면서 전혀 고쳐지지 않았습니다. 참고로 테스트 환경은 3.2.5 입니다.

신고

'Hibernate' 카테고리의 다른 글

HQL - update, delete 절  (0) 2008.04.20
HQL - 식별자 프로퍼티 참조  (0) 2008.04.17
HQL - 집계 함수, group by, having  (0) 2008.04.16
HQL - 컬렉션 필터  (0) 2008.04.13
HQL - fetch  (0) 2008.04.13
HQL - select 절  (0) 2008.04.13
Posted by 째코
지원 되는 집계 함수
  • avg(...), sum(...), min(...), max(...)
  • count(*)
  • count(...), count(distinct ...), count(all...)

통합 테스트
Seller s = (Seller)session.get(Seller.class, 1);
Map map = (Map)session.createFilter(s.getItems(),
                            "select new map(count(*) as count, " +
                                                    "avg(price) as avg, " +
                                                    "sum(price) as sum, " +
                                                    "min(price) as min, " +
                                                    "max(price) as max)").uniqueResult();
       
List list = session.createQuery("select new map(s.id as sellerId, " +
                                                       "count(i) as itemCount, " +
                                                       "max(i.price) as maxPrice, " +
                                                       "min(i.price) as minPrice, " +
                                                       "avg(i.price) as avgPrice) " +
                                                       "from Seller s join s.items i " +
                                                       "where i.price > 3000 " +
                                                       "group by s " +
                                                       "having max(i.price) > 4000").list();
System.out.println(map);
System.out.println(list);


출력 결과
{sum=27500, min=500, max=5000, avg=2750.0, count=10}

[{sellerId=1, maxPrice=5000, itemCount=4, minPrice=3500, avgPrice=4250.0},
{sellerId=2, maxPrice=5000, itemCount=4, minPrice=3500, avgPrice=4250.0},
{sellerId=3, maxPrice=5000, itemCount=4, minPrice=3500, avgPrice=4250.0},
{sellerId=4, maxPrice=5000, itemCount=4, minPrice=3500, avgPrice=4250.0},
{sellerId=5, maxPrice=5000, itemCount=4, minPrice=3500, avgPrice=4250.0}]

신고

'Hibernate' 카테고리의 다른 글

HQL - update, delete 절  (0) 2008.04.20
HQL - 식별자 프로퍼티 참조  (0) 2008.04.17
HQL - 집계 함수, group by, having  (0) 2008.04.16
HQL - 컬렉션 필터  (0) 2008.04.13
HQL - fetch  (0) 2008.04.13
HQL - select 절  (0) 2008.04.13
Posted by 째코
컬렉션 필터(session.createFilter())는 연관 컬렉션 객체를 조회할 때 조건을 주거나 페이징 처리를 하는 등 말 그대로 필터링 할 때 사용 합니다.

createFilter() 메서드는 createQuery() 메서드와 마찬가지로 Query 타입의 인스턴스를 리턴하기 때문에 기존 방식 그대로 사용 가능 합니다. 첫번째 인자는 조회 대상인 컬렉션, 두번째 인자는 hql 입니다.
Seller s = (Seller)session.get(Seller.class, 1);
List<Item> items = session.createFilter(s.getItems(), "order by this.price DESC").list();
판매자의 아이템들을 조회 하는데 필터를 이용해 가격을 내림차순으로 정렬하고 있습니다.
이 때 돌려지는 리스트는 createFilter() 메서드로 전달되는 컬렉션에 대한 사본 입니다.
그리고 hql 에서는 this 키워드를 이용하여 컬렉션 요소인 Item을 참조할 수 있습니다.

hql이 없더라도 상관 없습니다. 단순 페이징만으로도 아주 유용 합니다.
session.createFilter(s.getItems(), "")
    .setFirstResult(0)
    .setMaxResults(5)
    .list();

createFilter() 메서드는 기본적으로 다음과 같은 조건을 생성 합니다.
? 에 오는 값은 당연히 부모 객체의 식별 값 입니다.
from Item i where i.seller.id = ?

이미 where 절이 생성된다고 해서 조건을 추가할 수 없는 건 아닙니다.
자동으로 기존에 생성된 where 절에 조건이 추가 됩니다.
session.createFilter(s.getItems(), "where this.price > 3000").list();

컬렉션 필터라고 해서 반드시 컬렉션 요소만 조회할 수 있는건 아닙니다.
select 절을 그대로 사용할 수 있으므로 특정 프로퍼티만 조회할 수 있습니다.
session.createFilter(s.getItems(), "select this.price").list();
select 절만 있어도 기본으로 생성되는 where 절이 자동으로 붙습니다.

select 절을 사용할 때 where 절도 쓸 수 있습니다.
session.createFilter(s.getItems(), "select this.price where this.price > 3000").list();
이번에도 역시 기본으로 생성되는 where 절은 중간에 자동으로 붙습니다.

order by 까지 쓸 수 있습니다. 사실 어떤 hql이든 다 됩니다.
session.createFilter(s.getItems(), "select this.price where this.price > 3000 order by this.price DESC").list();


컬렉션 필터는 연관 컬렉션 객체를 페이징 할 수 있다는게 가장 큰 매력인거 같습니다.
신고

'Hibernate' 카테고리의 다른 글

HQL - 식별자 프로퍼티 참조  (0) 2008.04.17
HQL - 집계 함수, group by, having  (0) 2008.04.16
HQL - 컬렉션 필터  (0) 2008.04.13
HQL - fetch  (0) 2008.04.13
HQL - select 절  (0) 2008.04.13
HQL - join  (0) 2008.04.13
Posted by 째코

HQL - fetch

Hibernate 2008.04.13 02:08
hql에서 연관 객체를 조회하는 방식을 결정할 수 있습니다.
객체를 조회하는 방식에 대해서는 이전에 다뤘던 늦은로딩과 조회방식을 참고하는걸 추천 합니다.
hql에서는 join fetch, left join fetch 키워드를 사용하여 조회 방식을 결정 합니다. fetch 키워드를 사용한다는 의미는 늦은로딩을 하지 않고 내부조인 또는 외부조인으로 연관 객체를 한번에 로딩하겠다는 의미 입니다.

다음 hql은 내부조인으로 모든 객체를 한번에 가져 옵니다.
from Seller s join fetch s.items

외부 조인을 사용할 수도 있습니다.
from Seller s left join fetch s.items

lazy 속성이 false일 때 다음 두 hql은 동일한 SQL을 실행 합니다.
from Seller s join fetch s.items
from Seller s join s.items
하지만 fetch 키워드를 사용하면 연관 객체가 결과 리스트에 포함되지 않습니다.
즉 결과 리스트에 Seller 객체만 담겨 있습니다.

1-n 관계에서는 부모객체가 중복되서 나타나므로 select 절에서 중복을 제거해야 합니다.
select s distinct from Seller s join fetch s.items
수행되는 SQL에 distinct 키워드가 포함되지만 의미는 없습니다. 부모 객체의 중복 제거 작업은 메모리상에서 이루어 집니다. 하지만 조회되는 행들 자체가 중복이 아니기에 큰 문제는 없습니다.

래퍼런스에는 불가능하다고 나와 있지만 페이징도 가능 합니다.
session.createQuery("from Seller s join fetch s.items")
    .setFirstResult(5)
    .setMaxResults(20);
fetch 키워드를 사용하든 안하든 일단 조인이기 때문에 Seller 객체는 중복되서 나타날 것 입니다.
그래서 fetch 키워드를 사용하지 않을때는 select 절에서 Seller 객체만 조회한후 distinct 키워드를 이용해 중복을 제거한 뒤 페이징을 했었습니다. 하지만 fetch 키워드를 사용하면 상황이 다릅니다. fetch 라는 특성상 연관객체는 무조건 결과 행에 포함되기 때문에 Seller 객체의 중복을 결과 행에서 제거할 수가 없습니다. 하이버네이트는 fetch 사용시 페이징을 사용하면 일단 메모리상에서 Seller 객체의 중복을 제거한 뒤 메모리상에서 페이징을 합니다. 데이터가 많을 때는 사용을 자체해야 합니다.

1-1 관계나 n-1 관계에서는 실행되는 SQL에서 페이징을 하며 결과는 정상적 입니다.
기준이 Item 객체이기 때문에 결과 행에서 Item 객체의 중복은 없습니다.
session.createQuery("from Item i join fetch i.seller s where s.id = 5")
    .setFirstResult(0)
    .setMaxResults(10);

fetch 키워드 사용시 with 조건은 사용할 수 없습니다.
사용하면 예외가 발생하며 이런 메세지가 등장 합니다.
with-clause not allowed on fetched associations; use filters
필터를 사용하라네요...


주의사항
래퍼런스에 fetch 키워드 사용시 아래의 오퍼레이션은 사용할 수 없다고 나와 있습니다.
몇몇은 이미 위에서 언급된 내용들 입니다.
  • iterate() 사용 불가
  • 페이징은 결과가 기대하는대로 나오지 않음
  • with 조건 사용 불가
  • bag 매핑들에 대해 예기치 않은 결과가 발생
  • full join fetch와 right join fetch는 의미가 없음

신고

'Hibernate' 카테고리의 다른 글

HQL - 집계 함수, group by, having  (0) 2008.04.16
HQL - 컬렉션 필터  (0) 2008.04.13
HQL - fetch  (0) 2008.04.13
HQL - select 절  (0) 2008.04.13
HQL - join  (0) 2008.04.13
HQL - where 절  (0) 2008.04.13
Posted by 째코


티스토리 툴바