mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-03-03 16:29:13 +00:00
git-svn-id: https://svn.jboss.org/repos/hibernate/trunk/Hibernate3/doc@7522 1b8cb986-b30d-0410-93ca-fae66ebed9b2
1087 lines
50 KiB
XML
1087 lines
50 KiB
XML
<chapter id="queryhql">
|
|
<title>HQL: Hibernate Query Language</title>
|
|
|
|
<para>
|
|
Hibernate는 (아주 의도적으로) SQL과 매우 흡사하게 보이는 극히 강력한 질의 언어를 구비하고 있다. 그러나 그 구문에 의해 우롱당하지 말라;
|
|
HQL은 상속, 다형성 그리고 연관과 같은 개념들을 이해하여서, 전체적으로 객체 지향적이다.
|
|
</para>
|
|
|
|
<sect1 id="queryhql-casesensitivity">
|
|
<title>대소문자 구분</title>
|
|
|
|
<para>
|
|
질의들은 Java 클래스들과 프로퍼티들의 이름들을 제외하면 대소문자를 구분하지 않는다. 따라서 <literal>SeLeCT</literal>는
|
|
<literal>SELECT</literal>와 같고 <literal>SELECT</literal>와도 같지만 <literal>org.hibernate.eg.FOO</literal>는
|
|
<literal>org.hibernate.eg.Foo</literal>과 같지 않고 <literal>foo.barSet</literal>은
|
|
<literal>foo.BARSET</literal>과 같지 않다.
|
|
</para>
|
|
|
|
<para>
|
|
이 매뉴얼은 소문자 HQL 키워드를 사용한다. 몇몇 사용자들은 보다 나은 가독성을 위해 대문자 키워드들을 가진 질의들을 찾지만, 우리는
|
|
자바 코드 속에 삽입될 때 이 컨벤션이 추하다는 점을 발견한다.
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="queryhql-from">
|
|
<title>from 절</title>
|
|
|
|
<para>
|
|
가장 간단한 가능한 Hibernate 질의는 다음 형식이다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from eg.Cat]]></programlisting>
|
|
|
|
<para>
|
|
이것은 <literal>eg.Cat</literal> 클래스의 모든 인스턴스들을 간단하게 반환한다. 우리는 대개 클래스 이름을 수식할 필요가 없다.
|
|
왜냐하면, <literal>auto-import</literal>가 디폴트이기 때문이다. 따라서 우리는 대개 항상 단지 다음과 같이 작성한다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Cat]]></programlisting>
|
|
|
|
<para>
|
|
대개 당신은 한 개의 <emphasis>alias</emphasis>를 할당할 필요가 있을 것이다. 왜냐하면 당신은 질의의 다른 부분들에서
|
|
<literal>Cat</literal>을 참조하고자 원할 것이기 때문이다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Cat as cat]]></programlisting>
|
|
|
|
<para>
|
|
이 질의는 alias <literal>cat</literal>을 <literal>Cat</literal> 인스턴스들에 할당하여서, 우리는 나중에 질의 속에서
|
|
그 alias를 사용할 수 있을 것이다. <literal>as</literal> 키워드는 옵션이다; 우리는 또한 다음과 같이 작성할 수 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Cat cat]]></programlisting>
|
|
|
|
<para>
|
|
여러 개의 클래스들은 cartesian product(카티젼 곱) 또는 "크로스" 조인으로 귀결되어 나타날 수도 있다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Formula, Parameter]]></programlisting>
|
|
<programlisting><![CDATA[from Formula as form, Parameter as param]]></programlisting>
|
|
|
|
<para>
|
|
로컬 변수들에 대한 Java 네이밍 표준들과 일치되게, 첫 소문자를 사용하여 질의 alias들을 명명하는 것은 좋은 습관으로 간주된다
|
|
(예를 들면 <literal>domesticCat</literal>).
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="queryhql-joins" revision="1">
|
|
<title>연관들과 조인들</title>
|
|
|
|
<para>
|
|
우리는 또한 <literal>join</literal>을 사용하여 , 연관된 엔티티들에 또는 값들을 가진 콜렉션의 요소들에도 alias들을 할당할 수도
|
|
있다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Cat as cat
|
|
inner join cat.mate as mate
|
|
left outer join cat.kittens as kitten]]></programlisting>
|
|
|
|
<programlisting><![CDATA[from Cat as cat left join cat.mate.kittens as kittens]]></programlisting>
|
|
|
|
<programlisting><![CDATA[from Formula form full join form.parameter param]]></programlisting>
|
|
|
|
<para>
|
|
지원되는 join 타입들은 ANSI SQL로부터 빌려왔다
|
|
</para>
|
|
|
|
<itemizedlist spacing="compact">
|
|
<listitem>
|
|
<para>
|
|
<literal>inner join</literal>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>left outer join</literal>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>right outer join</literal>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>full join</literal> (대개 유용하지 않음)
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
<literal>inner join</literal>, <literal>left outer join</literal>, 그리고 <literal>right outer join</literal>
|
|
구조체들이 약칭될 수 있다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Cat as cat
|
|
join cat.mate as mate
|
|
left join cat.kittens as kitten]]></programlisting>
|
|
|
|
<para>
|
|
당신은 HQL <literal>with</literal> 키워드를 사용하여 특별한 조인 조건들을 제공할 수 있다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Cat as cat
|
|
left join cat.kittens as kitten
|
|
with kitten.bodyWeight > 10.0]]></programlisting>
|
|
|
|
<para>
|
|
게다가, "fetch" join은 값들을 가진 콜렉션들이나 연관관계들이 한 개의 select를 사용하여, 그것들의 부모 객체들에 따라 초기화 되는
|
|
것을 허용해준다. 이것은 콜렉션의 경우에 특히 유용하다. 그것은 연관관계들과 콜렉션들에 대한 매핑 파일의 outer join과 lazy 선언들을
|
|
효율적으로 오버라이드 시킨다. 추가 정보는 <xref linkend="performance-fetching"/>을 보라.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Cat as cat
|
|
inner join fetch cat.mate
|
|
left join fetch cat.kittens]]></programlisting>
|
|
|
|
<para>
|
|
fetch join은 대개 alias를 할당할 필요가 없다. 왜냐하면, 연관된 객체들이 <literal>where</literal> 절(또는 어떤 다른 절)
|
|
속에 사용되지 않을 것이기 때문이다. 또한 연관된 객체들은 질의 결과들 속에 직접 반환되지 않는다. 대신 그것들은 부모 객체를 통해
|
|
접근될 수 있다. 우리가 alias를 필요로 할 수 있는 유일한 이유는 더 많은 콜렉션들을 재귀적으로 조인 페칭시키는 경우이다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Cat as cat
|
|
inner join fetch cat.mate
|
|
left join fetch cat.kittens child
|
|
left join fetch child.kittens]]></programlisting>
|
|
|
|
<para>
|
|
<literal>fetch</literal> 구조체는 <literal>scroll()</literal>
|
|
또는 <literal>iterate()</literal>를 사용하여 호출된 질의들 내에 사용될 수 없음을 노트하라. <literal>fetch</literal>는
|
|
<literal>setMaxResults()</literal> 또는 <literal>setFirstResult()</literal>와 함께 사용될 수도 없을 것이다.
|
|
<literal>fetch</literal>는 특별한 용도의 <literal>with</literal> 조건과도 함께 사용될 수 없다.한 개의 질의 내에 하나
|
|
이상의 콜렉션을 조인 페칭시켜 카티젼 곱을 생성시키는 것이 가능한데, 이 경우에 주의하라. 다중 콜렉션 role들을 조인 페칭시키는 것은
|
|
또한 때때로 bag 매핑들에 대해 예기치 않은 결과들을 가져다주기 때문에, 당신이 이 경우에 당신의 질의들을 처방하는 방법에 대해 주의하라.
|
|
마지막으로 <literal>full join fetch</literal>와 <literal>right join fetch</literal>는 의미가 없다.
|
|
</para>
|
|
|
|
<para>
|
|
만일 당신이 (바이트코드 방편으로) property-레벨 lazy 페칭을 사용할 경우, Hibernate로 하여금 <literal>fetch all properties</literal>를
|
|
사용하여 (첫 번째 질의에서) lazy 프로퍼티들을 즉시 페치하도록 강제시키는 것이 가능하다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Document fetch all properties order by name]]></programlisting>
|
|
<programlisting><![CDATA[from Document doc fetch all properties where lower(doc.name) like '%cats%']]></programlisting>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="queryhql-select">
|
|
<title>select 절</title>
|
|
|
|
<para>
|
|
<literal>select</literal> 절은 질의 결과 셋 속에 반환할 객체들과 프로퍼티들이 어느 것인지를 골라 내도록 강제한다. 다음을
|
|
검토하자:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select mate
|
|
from Cat as cat
|
|
inner join cat.mate as mate]]></programlisting>
|
|
|
|
<para>
|
|
질의는 다른 <literal>Cat</literal>들의 <literal>mate</literal>들을 select 할 것이다. 실제로 당신은 이 질의들을 다음과
|
|
같이 보다 축약형으로 표현할수도 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select cat.mate from Cat cat]]></programlisting>
|
|
|
|
<para>
|
|
질의들은 컴포넌트 타입의 프로퍼티들을 포함하는 임의의 값 타입의 프로퍼티들을 반환할 수도 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select cat.name from DomesticCat cat
|
|
where cat.name like 'fri%']]></programlisting>
|
|
|
|
<programlisting><![CDATA[select cust.name.firstName from Customer as cust]]></programlisting>
|
|
|
|
<para>
|
|
<literal>Family</literal> 클래스가 적당한 생성자를 갖고 있음을 가정하면,
|
|
질의들은 여러 객체들 그리고/또는 프로퍼티들을 <literal>Object[]</literal> 타입의 배열로서,
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select mother, offspr, mate.name
|
|
from DomesticCat as mother
|
|
inner join mother.mate as mate
|
|
left outer join mother.kittens as offspr]]></programlisting>
|
|
|
|
<para>
|
|
또는 <literal>List</literal>로서,
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select new list(mother, offspr, mate.name)
|
|
from DomesticCat as mother
|
|
inner join mother.mate as mate
|
|
left outer join mother.kittens as offspr]]></programlisting>
|
|
|
|
<para>
|
|
또는 실제 typesafe 자바 객체로서,
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select new Family(mother, mate, offspr)
|
|
from DomesticCat as mother
|
|
join mother.mate as mate
|
|
left join mother.kittens as offspr]]></programlisting>
|
|
|
|
<para>
|
|
반환할 수도 있다.
|
|
</para>
|
|
|
|
<para>
|
|
당신은 <literal>as</literal>를 사용하여 select되는 표현식들에 alias들을 할당할 수 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n
|
|
from Cat cat]]></programlisting>
|
|
|
|
<para>
|
|
다음은 <literal>select new map</literal>과 함께 사용될 때 가장 유용하다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select new map( max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n )
|
|
from Cat cat]]></programlisting>
|
|
|
|
<para>
|
|
이 질의는 select된 값들에 대한 alias로부터 한 개의 <literal>Map</literal>을 반환한다.
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="queryhql-aggregation">
|
|
<title>집계 함수들</title>
|
|
|
|
<para>
|
|
HQL 질의들은 프로퍼티들에 대한 집계(aggregate) 함수들의 결과들을 반환할수도 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select avg(cat.weight), sum(cat.weight), max(cat.weight), count(cat)
|
|
from Cat cat]]></programlisting>
|
|
|
|
<!-- NO LONGER SUPPORTED
|
|
<para>
|
|
Collections may also appear inside aggregate functions in the <literal>select</literal>
|
|
clause.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select cat, count( elements(cat.kittens) )
|
|
from Cat cat group by cat]]></programlisting>
|
|
-->
|
|
|
|
<para>
|
|
지원되는 집계 함수들은 다음과 같다
|
|
</para>
|
|
|
|
<itemizedlist spacing="compact">
|
|
<listitem>
|
|
<para>
|
|
<literal>avg(...), sum(...), min(...), max(...)</literal>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>count(*)</literal>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>count(...), count(distinct ...), count(all...)</literal>
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
당신은 select 절 속에 산술 연산자들, 연결 연산자, 그리고 인지된 SQL 함수들을 사용할 수 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select cat.weight + sum(kitten.weight)
|
|
from Cat cat
|
|
join cat.kittens kitten
|
|
group by cat.id, cat.weight]]></programlisting>
|
|
|
|
<programlisting><![CDATA[select firstName||' '||initial||' '||upper(lastName) from Person]]></programlisting>
|
|
|
|
<para>
|
|
<literal>distinct</literal> 키워드와 all <literal>all</literal>가 사용될 수 있고 SQL의 경우와 동일한 의미를 갖는다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select distinct cat.name from Cat cat
|
|
|
|
select count(distinct cat.name), count(cat) from Cat cat]]></programlisting>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="queryhql-polymorphism">
|
|
<title>Polymorphic(다형성) 질의들</title>
|
|
|
|
<para>
|
|
다음과 같은 질의:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Cat as cat]]></programlisting>
|
|
|
|
<para>
|
|
은 <literal>Cat</literal>의 인스턴스들 뿐만 아니라, 또한 <literal>DomesticCat</literal>과 같은 서브클래스들 또한
|
|
반환한다. Hibernate 질의들은 <literal>from</literal> 절 내에 <emphasis>임의의</emphasis> 자바 클래스나 인터페이스를
|
|
명명할 수 있다. 질의는 그 클래스를 확장하거나 그 인터페이스를 구현하는 모든 영속 클래스들의 인스턴스들을 반환할 것이다. 다음 질의는
|
|
모든 영속 객체들을 반환할 것이다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from java.lang.Object o]]></programlisting>
|
|
|
|
<para>
|
|
인터페이스 <literal>Named</literal>는 여러 가지 영속 클래스들에 의해 구현될 수도 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Named n, Named m where n.name = m.name]]></programlisting>
|
|
|
|
<para>
|
|
이들 마지막 두 개의 질의들은 하나 이상의 SQL <literal>SELECT</literal>를 필요로 할 것임을 노트하라. 이것은 <literal>order by</literal>
|
|
절이 정확하게 전체 결과 셋을 순서지우지 않음을 의미한다.(그것은 또한 당신이 <literal>Query.scroll()</literal>을 사용하여
|
|
이들 질의들을 호출할 수 없음을 의미한다).
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="queryhql-where">
|
|
<title>where 절</title>
|
|
|
|
<para>
|
|
<literal>where</literal> 절은 반환된 인스턴스들의 목록을 제한시키는 것을 당신에게 허용해준다. 만일 alias가 존재하지 않을 경우,
|
|
당신은 이름에 의해 프로퍼티들을 참조할 수도 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Cat where name='Fritz']]></programlisting>
|
|
|
|
<para>
|
|
만일 한 개의 alias가 존재할 경우, 하나의 수식어가 붙은 프로퍼티 이름을 사용하라:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Cat as cat where cat.name='Fritz']]></programlisting>
|
|
|
|
<para>
|
|
는 'Fritz'로 명명된 <literal>Cat</literal>의 인스턴스들을 반환한다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select foo
|
|
from Foo foo, Bar bar
|
|
where foo.startDate = bar.date]]></programlisting>
|
|
|
|
<para>
|
|
는 <literal>Foo</literal>의 <literal>startDate</literal> 프로퍼티와 동일한 <literal>date</literal> 프로퍼티를
|
|
가진 <literal>bar</literal>의 인스턴스가 존재하는 <literal>Foo</literal>의 모든 인스턴스를 반환할 것이다. 합성 경로
|
|
표현식들은 <literal>where</literal> 절을 매우 강력하게 만들어준다. 다음을 검토하자:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Cat cat where cat.mate.name is not null]]></programlisting>
|
|
|
|
<para>
|
|
이 질의는 테이블 (inner) join을 가진 SQL 질의로 번역된다. 만일 당신이 다음과 같은 어떤 것을 작성했다면
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Foo foo
|
|
where foo.bar.baz.customer.address.city is not null]]></programlisting>
|
|
|
|
<para>
|
|
당신은 SQL에서 네 개의 테이블 join들을 필요로 하는 하나의 질의로 끝낼 것이다.
|
|
</para>
|
|
|
|
<para>
|
|
<literal>=</literal> 연산자는 프로퍼티들 뿐만 아니라 또한 인스턴스들을 비교하는데 사용될 수 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Cat cat, Cat rival where cat.mate = rival.mate]]></programlisting>
|
|
|
|
<programlisting><![CDATA[select cat, mate
|
|
from Cat cat, Cat mate
|
|
where cat.mate = mate]]></programlisting>
|
|
|
|
<para>
|
|
특별한 프로퍼티(소문자) <literal>id</literal>는 객체의 유일 식별자를 참조하는데 사용될 수 있다.(당신은 또한 그것의 프로퍼티
|
|
이름을 사용할 수도 있다.)
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Cat as cat where cat.id = 123
|
|
|
|
from Cat as cat where cat.mate.id = 69]]></programlisting>
|
|
|
|
<para>
|
|
두 번째 질의가 효율적이다. 테이블 join이 필요 없다!
|
|
</para>
|
|
|
|
<para>
|
|
composite identifier(합성 식별자)들의 프로퍼티들이 또한 사용될 수 있다. <literal>Person</literal>이
|
|
<literal>country</literal>와 <literal>medicareNumber</literal>로 구성된 composite identifier를 갖는다고
|
|
가정하자.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from bank.Person person
|
|
where person.id.country = 'AU'
|
|
and person.id.medicareNumber = 123456]]></programlisting>
|
|
|
|
<programlisting><![CDATA[from bank.Account account
|
|
where account.owner.id.country = 'AU'
|
|
and account.owner.id.medicareNumber = 123456]]></programlisting>
|
|
|
|
<para>
|
|
다시 한번, 두 번째 질의는 테이블 join을 필요로 하지 않는다.
|
|
</para>
|
|
|
|
<para>
|
|
마찬가지로, 특별한 프로퍼티 <literal>class</literal>는 다형적인 영속성(polymorphic persistence)의 경우에 인스턴스의
|
|
판별자(discriminator) 값에 액세스한다. where 절 속에 삽입된 Java 클래스 이름은 그것의 판별자(discriminator) 값으로
|
|
변환될 것이다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Cat cat where cat.class = DomesticCat]]></programlisting>
|
|
|
|
<para>
|
|
당신은 또한 컴포넌트들 또는 composite 사용자 정의 타입들의 (그리고 컴포넌트들의 컴포넌트들, 기타의) 프로퍼티들을
|
|
지정할 수도 있다. (컴포넌트의 프로퍼티와은 반대로) 컴포넌트 타입의 프로퍼티로 끝나는 경로-표현식을 사용하려고 결코 시도하지 말라.
|
|
예를 들어, 만일 <literal>store.owner</literal>가 컴포넌트 <literal>address</literal>를 가진 엔티티일 경우
|
|
</para>
|
|
|
|
<programlisting><![CDATA[store.owner.address.city // okay
|
|
store.owner.address // error!]]></programlisting>
|
|
|
|
<para>
|
|
"임의의" 타입은 다음 방법으로 join을 표현하는 것을 우리에게 허용해주는, 특별한 프로퍼티들 <literal>id</literal>와
|
|
<literal>class</literal>를 갖는다(여기서 <literal>AuditLog.item</literal>은 <literal><any></literal>로
|
|
매핑된 프로퍼티이다).
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from AuditLog log, Payment payment
|
|
where log.item.class = 'Payment' and log.item.id = payment.id]]></programlisting>
|
|
|
|
<para>
|
|
<literal>log.item.class</literal>와 <literal>payment.class</literal>는 위의 질의 내에서 완전히 다른 데이터베이스
|
|
컬럼들의 값들을 참조할 것임을 노트하라.
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="queryhql-expressions">
|
|
<title>표현식들</title>
|
|
|
|
<para>
|
|
<literal>where</literal> 절 속에 허용되는 표현식들은 당신이 SQL로 작성할 수 있는 대부분의 종류의 것들을 포함한다:
|
|
</para>
|
|
|
|
<itemizedlist spacing="compact">
|
|
<listitem>
|
|
<para>
|
|
산술 연산자들 <literal>+, -, *, /</literal>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
바이너리 비교 연산자들 <literal>=, >=, <=, <>, !=, like</literal>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
논리 연산들 <literal>and, or, not</literal>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
그룹핑을 나타내는 괄호들 <literal>( )</literal>, indicating grouping
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>in</literal>,
|
|
<literal>not in</literal>,
|
|
<literal>between</literal>,
|
|
<literal>is null</literal>,
|
|
<literal>is not null</literal>,
|
|
<literal>is empty</literal>,
|
|
<literal>is not empty</literal>,
|
|
<literal>member of</literal> and
|
|
<literal>not member of</literal>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
"간단한" 경우, <literal>case ... when ... then ... else ... end</literal>, 그리고
|
|
"검색인" 경우, <literal>case when ... then ... else ... end</literal>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
문자열 연결 <literal>...||...</literal> or <literal>concat(...,...)</literal>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>current_date()</literal>, <literal>current_time()</literal>,
|
|
<literal>current_timestamp()</literal>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>second(...)</literal>, <literal>minute(...)</literal>,
|
|
<literal>hour(...)</literal>, <literal>day(...)</literal>,
|
|
<literal>month(...)</literal>, <literal>year(...)</literal>,
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
EJB-QL 3.0에 의해 정의된 임의의 함수 또는 오퍼레이터: <literal>substring(), trim(),
|
|
lower(), upper(), length(), locate(), abs(), sqrt(), bit_length(), mod()</literal>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>coalesce()</literal> 그리고 <literal>nullif()</literal>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
numeric 값들이나 temporal 값들을 가독성 있는 문자열로 변환시키는 <literal>str()</literal>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
조인된 인덱싱된 콜렉션의 alias들에 적용되는, HQL <literal>index()</literal> 함수
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
콜렉션 값을 가진 경로 표현식들을 취하는 HQL 함수들 : <literal>some, all, exists, any, in</literal>을
|
|
사용하여 정량화 될 수 있는 특별한 <literal>elements()</literal>와 <literal>indices</literal>
|
|
함수들과 함께 <literal>size(), minelement(), maxelement(), minindex(), maxindex()</literal>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>cast(... as ...)</literal>, 여기서 두번 째 아규먼트는 Hibernate 타입의 이름이고,
|
|
ANSI <literal>cast()</literal>와 <literal>extract()</literal>가 기본 데이터베이스에 의해 지원될 경우에는
|
|
<literal>extract(... from ...)</literal>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
조인된 인덱싱된 콜렉션의 alias들을 적용하는 HQL <literal>index()</literal> 함수
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
콜렉션 값 경로 표현식들을 취하는 HQL 함수들: <literal>some, all, exists, any, in</literal>을 사용하여
|
|
양이 한정될 수 있는 특별한 <literal>elements()</literal> 및 <literal>indices</literal> 함수들과 함께
|
|
<literal>size(), minelement(), maxelement(), minindex(), maxindex()</literal> 함수들.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>sign()</literal>, <literal>trunc()</literal>, <literal>rtrim()</literal>,
|
|
<literal>sin()</literal>과 같이 임의의 데이터베이스-지원 SQL 스칼라 함수
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
JDBC-스타일 위치 파라미터들 <literal>?</literal>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
명명된 파라미터들 <literal>:name</literal>, <literal>:start_date</literal>, <literal>:x1</literal>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
SQL 리터럴들 <literal>'foo'</literal>, <literal>69</literal>, <literal>6.66E+2</literal>,
|
|
<literal>'1970-01-01 10:00:01.0'</literal>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Java <literal>public static final</literal> 상수들. <literal>eg.Color.TABBY</literal>
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
<literal>in</literal> 과 <literal>between</literal>은 다음과 같이 사용될 수 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from DomesticCat cat where cat.name between 'A' and 'B']]></programlisting>
|
|
|
|
<programlisting><![CDATA[from DomesticCat cat where cat.name in ( 'Foo', 'Bar', 'Baz' )]]></programlisting>
|
|
|
|
<para>
|
|
그리고 부정형들은 다음과 같이 작성될 수 있다
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from DomesticCat cat where cat.name not between 'A' and 'B']]></programlisting>
|
|
|
|
<programlisting><![CDATA[from DomesticCat cat where cat.name not in ( 'Foo', 'Bar', 'Baz' )]]></programlisting>
|
|
|
|
<para>
|
|
마찬가지로, <literal>is null</literal>과 <literal>is not null</literal>은 null 값들을 테스트하는데 사용될 수 있다.
|
|
</para>
|
|
|
|
<para>
|
|
Boolean들은 Hibernate 구성 내에 HQL 질의 치환들을 선언함으로써 표현식들 내에 쉽게 사용될 수 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<property name="hibernate.query.substitutions">true 1, false 0</property>]]></programlisting>
|
|
|
|
<para>
|
|
이것은 키워드 <literal>true</literal>와 <literal>false</literal> 키워드들을 이 HQL로부터 번역된 SQL에서
|
|
리터럴 <literal>1</literal>과 <literal>0</literal>으로 대체될 것이다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Cat cat where cat.alive = true]]></programlisting>
|
|
|
|
<para>
|
|
당신은 특별한 프로퍼티 <literal>size</literal>로서 또는 특별한 <literal>size()</literal> 함수로서 콜렉션의 사이즈를
|
|
테스트할 수 있다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Cat cat where cat.kittens.size > 0]]></programlisting>
|
|
|
|
<programlisting><![CDATA[from Cat cat where size(cat.kittens) > 0]]></programlisting>
|
|
|
|
<para>
|
|
인덱싱된 콜렉션들에 대해, 당신은<literal>minindex</literal>와 <literal>maxindex</literal> 함수들을 사용하여
|
|
최소 인덱스과 최대 인덱스를 참조할 수 있다. 유사하게 당신은 <literal>minelement</literal>와
|
|
<literal>maxelement</literal> 함수를 사용하여 기본 타입을 가진 콜렉션의 최소 요소 및 최대 요소를 참조할 수 있다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Calendar cal where maxelement(cal.holidays) > current date]]></programlisting>
|
|
|
|
<programlisting><![CDATA[from Order order where maxindex(order.items) > 100]]></programlisting>
|
|
|
|
<programlisting><![CDATA[from Order order where minelement(order.items) > 10000]]></programlisting>
|
|
|
|
<para>
|
|
SQL 함수들 <literal>any, some, all, exists, in</literal>은 콜렉션의 요소 또는 인덱스 세트(<literal>elements</literal>
|
|
함수와 <literal>indices</literal> 함수), 또는 서브질의의 결과를 전달했을 때 지원된다(아래를 보라).
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select mother from Cat as mother, Cat as kit
|
|
where kit in elements(foo.kittens)]]></programlisting>
|
|
|
|
<programlisting><![CDATA[select p from NameList list, Person p
|
|
where p.name = some elements(list.names)]]></programlisting>
|
|
|
|
<programlisting><![CDATA[from Cat cat where exists elements(cat.kittens)]]></programlisting>
|
|
|
|
<programlisting><![CDATA[from Player p where 3 > all elements(p.scores)]]></programlisting>
|
|
|
|
<programlisting><![CDATA[from Show show where 'fizard' in indices(show.acts)]]></programlisting>
|
|
|
|
<para>
|
|
이들 구조체들-<literal>size</literal>, <literal>elements</literal>, <literal>indices</literal>,
|
|
<literal>minindex</literal>, <literal>maxindex</literal>, <literal>minelement</literal>,
|
|
<literal>maxelement</literal>-는 Hibernate3에서 where 절 내에서만 사용될 것임을 노트하라.
|
|
</para>
|
|
|
|
<para>
|
|
인덱싱 된 콜렉션들의 요소들(배열들, 리스트들, map들)은 인덱스에 의해 참조될 수 있다(where 절 안에서만):
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Order order where order.items[0].id = 1234]]></programlisting>
|
|
|
|
<programlisting><![CDATA[select person from Person person, Calendar calendar
|
|
where calendar.holidays['national day'] = person.birthDay
|
|
and person.nationality.calendar = calendar]]></programlisting>
|
|
|
|
<programlisting><![CDATA[select item from Item item, Order order
|
|
where order.items[ order.deliveredItemIndices[0] ] = item and order.id = 11]]></programlisting>
|
|
|
|
<programlisting><![CDATA[select item from Item item, Order order
|
|
where order.items[ maxindex(order.items) ] = item and order.id = 11]]></programlisting>
|
|
|
|
<para>
|
|
<literal>[]</literal> 내부의 표현식은 산술 표현실일 수 있다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select item from Item item, Order order
|
|
where order.items[ size(order.items) - 1 ] = item]]></programlisting>
|
|
|
|
<para>
|
|
HQL은 또한 one-to-many 연관 또는 값들을 가진 콜렉션의 요소들에 대해 미리 만들어진 <literal>index()</literal> 함수를
|
|
제공한다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select item, index(item) from Order order
|
|
join order.items item
|
|
where index(item) < 5]]></programlisting>
|
|
|
|
<para>
|
|
기본 데이터베이스에 의해 제공되는 Scalar SQL 함수들이 사용될 수도 있다
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from DomesticCat cat where upper(cat.name) like 'FRI%']]></programlisting>
|
|
|
|
<para>
|
|
당신이 아직 이 모든 것을 납득하지 못한다면, SQL 내에서 다음 질의가 가독성이 얼마나 많고 적은지를 생각해보라:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select cust
|
|
from Product prod,
|
|
Store store
|
|
inner join store.customers cust
|
|
where prod.name = 'widget'
|
|
and store.location.name in ( 'Melbourne', 'Sydney' )
|
|
and prod = all elements(cust.currentOrder.lineItems)]]></programlisting>
|
|
|
|
<para>
|
|
<emphasis>힌트</emphasis> : 다음과 같은 어떤 것
|
|
</para>
|
|
|
|
<programlisting><![CDATA[SELECT cust.name, cust.address, cust.phone, cust.id, cust.current_order
|
|
FROM customers cust,
|
|
stores store,
|
|
locations loc,
|
|
store_customers sc,
|
|
product prod
|
|
WHERE prod.name = 'widget'
|
|
AND store.loc_id = loc.id
|
|
AND loc.name IN ( 'Melbourne', 'Sydney' )
|
|
AND sc.store_id = store.id
|
|
AND sc.cust_id = cust.id
|
|
AND prod.id = ALL(
|
|
SELECT item.prod_id
|
|
FROM line_items item, orders o
|
|
WHERE item.order_id = o.id
|
|
AND cust.current_order = o.id
|
|
)]]></programlisting>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="queryhql-ordering">
|
|
<title>order by 절</title>
|
|
|
|
<para>
|
|
질의에 의해 반환된 리스트는 반환된 클래스 또는 컴포넌트들의 프로퍼티에 의해 순서(ordering)지워질 수 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from DomesticCat cat
|
|
order by cat.name asc, cat.weight desc, cat.birthdate]]></programlisting>
|
|
|
|
<para>
|
|
<literal>asc</literal> 옵션 또는 <literal>desc</literal> 옵션은 각각 오름차순 또는 내림차순 정렬을 나타낸다.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 id="queryhql-grouping">
|
|
<title>group by 절</title>
|
|
|
|
<para>
|
|
aggregate 값들을 반환하는 질의는 반환된 클래스나 컴포넌트들의 프로퍼티에 의해 그룹지워질 수 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat)
|
|
from Cat cat
|
|
group by cat.color]]></programlisting>
|
|
|
|
<programlisting><![CDATA[select foo.id, avg(name), max(name)
|
|
from Foo foo join foo.names name
|
|
group by foo.id]]></programlisting>
|
|
|
|
<para>
|
|
또한 <literal>having</literal> 절이 허용된다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat)
|
|
from Cat cat
|
|
group by cat.color
|
|
having cat.color in (eg.Color.TABBY, eg.Color.BLACK)]]></programlisting>
|
|
|
|
<para>
|
|
SQL 함수들과 집계 함수들이 기본 데이터베이스에 의해 지원될 경우(예를 들어 MySQL은 지원되지 않는다)
|
|
<literal>having</literal> 절과 <literal>order by</literal> 절 속에 허용된다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select cat
|
|
from Cat cat
|
|
join cat.kittens kitten
|
|
group by cat
|
|
having avg(kitten.weight) > 100
|
|
order by count(kitten) asc, sum(kitten.weight) desc]]></programlisting>
|
|
|
|
<para>
|
|
<literal>group by</literal> 절도 <literal>order by</literal> 절 어느 것도 산술 표현식들을 포함할 수 없다는 점을
|
|
노트하라.
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="queryhql-subqueries" revision="2">
|
|
<title>서브질의들</title>
|
|
|
|
<para>
|
|
subselect들을 지원하는 데이터베이스들의 경우, Hibernate는 질의들 내에 서브질의들을 지원한다. 서브질의는 괄호로 묶여져야
|
|
한다(자주 SQL 집계함수 호출에 의해). 심지어 서로 상관된 서브질의들(외부 질의 내에서 alias를 참조하는 서브질의들)이 허용된다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Cat as fatcat
|
|
where fatcat.weight > (
|
|
select avg(cat.weight) from DomesticCat cat
|
|
)]]></programlisting>
|
|
|
|
<programlisting><![CDATA[from DomesticCat as cat
|
|
where cat.name = some (
|
|
select name.nickName from Name as name
|
|
)]]></programlisting>
|
|
|
|
<programlisting><![CDATA[from Cat as cat
|
|
where not exists (
|
|
from Cat as mate where mate.mate = cat
|
|
)]]></programlisting>
|
|
|
|
<programlisting><![CDATA[from DomesticCat as cat
|
|
where cat.name not in (
|
|
select name.nickName from Name as name
|
|
)]]></programlisting>
|
|
|
|
<programlisting><![CDATA[select cat.id, (select max(kit.weight) from cat.kitten kit)
|
|
from Cat as cat]]></programlisting>
|
|
|
|
<para>
|
|
select 리스트 내에 있는 하나 이상의 표현식을 가진 서브질의들의 경우에 당신은 tuple 생성자를 사용할 수 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Cat as cat
|
|
where not ( cat.name, cat.color ) in (
|
|
select cat.name, cat.color from DomesticCat cat
|
|
)]]></programlisting>
|
|
|
|
<para>
|
|
HQL 서브질의들이 select 절 또는 where 절 내에서만 일어날 수 있음을 노트하라.
|
|
</para>
|
|
|
|
<para>
|
|
(Oracle 또는 HSQL이 아닌) 몇몇 데이터베이스들 상에서, 당신은 다른 컨텍스트들 내에서, 예를 들면 component들이나 composite
|
|
사용자 타입들을 질의할 때 tuple 생성자들을 사용할 수 있음을 노트하라:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Person where name = ('Gavin', 'A', 'King')]]></programlisting>
|
|
|
|
<para>
|
|
이것을 더 풀어쓰면 다음과 동일하다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from Person where name.first = 'Gavin' and name.initial = 'A' and name.last = 'King')]]></programlisting>
|
|
|
|
<para>
|
|
당신이 이런 종류의 것을 행하는 것을 원하지 않을 수 있는 두 가지 좋은 이유들이 존재한다: 첫 번째로 데이터베이스 플랫폼들 사이에 완전하게
|
|
이식성이 없다; 두 번째로 그 질의는 이제 매핑 문서 속에 있는 프로퍼티들의 순서에 의존한다.
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="queryhql-examples">
|
|
<title>HQL 예제들</title>
|
|
|
|
<para>
|
|
|
|
Hibernate 질의들은 매우 강력하고 복잡할 수 있다. 사실, 질의 언어의 힘은 Hibernate의 주요 판매 포인트들 중 하나이다. 다음은
|
|
내가 최근의 프로젝트에서 사용했던 질의들과 매우 유사한 몇몇 예제 질의들이다. 당신이 작성하게 될 대부분의 질의들은 이것들보다 훨씬
|
|
간단하다는 점을 노트하라!
|
|
</para>
|
|
|
|
<para>
|
|
다음 질의는 특정 고객에 대한 모든 지불되지 않은 주문들의 주문 id, 항목들의 개수, 그리고 주문의 전체 합계값 그리고 주어진
|
|
최소 전체 합계를 전체 합계값에 따라 결과들을 순서지워서 반환한다. 가격 결정에 있어, 그것은 현재의 카타록을 사용한다.
|
|
귀결되는 SQL 질의는 <literal>ORDER</literal>, <literal>ORDER_LINE</literal>, <literal>PRODUCT</literal>,
|
|
<literal>CATALOG</literal>, <literal>PRICE</literal> 테이블들에 대한 네 개의 inner 조인들과 한 개의(상관지워지지
|
|
않은) subselect를 갖고 있다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select order.id, sum(price.amount), count(item)
|
|
from Order as order
|
|
join order.lineItems as item
|
|
join item.product as product,
|
|
Catalog as catalog
|
|
join catalog.prices as price
|
|
where order.paid = false
|
|
and order.customer = :customer
|
|
and price.product = product
|
|
and catalog.effectiveDate < sysdate
|
|
and catalog.effectiveDate >= all (
|
|
select cat.effectiveDate
|
|
from Catalog as cat
|
|
where cat.effectiveDate < sysdate
|
|
)
|
|
group by order
|
|
having sum(price.amount) > :minAmount
|
|
order by sum(price.amount) desc]]></programlisting>
|
|
|
|
<para>
|
|
괴물 같은 것! 실제로 실 생활에서, 나는 서브질의들을 매우 좋아하지 않아서, 나의 질의는 실제로 다음과 같았다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select order.id, sum(price.amount), count(item)
|
|
from Order as order
|
|
join order.lineItems as item
|
|
join item.product as product,
|
|
Catalog as catalog
|
|
join catalog.prices as price
|
|
where order.paid = false
|
|
and order.customer = :customer
|
|
and price.product = product
|
|
and catalog = :currentCatalog
|
|
group by order
|
|
having sum(price.amount) > :minAmount
|
|
order by sum(price.amount) desc]]></programlisting>
|
|
|
|
<para>
|
|
다음 질의는 현재 사용자에 의해 가장 최근의 상태 변경이 행해졌던 <literal>AWAITING_APPROVAL</literal> 상태에 있는 모든
|
|
지불들을 제외한, 각각의 상태에 있는 지불들의 개수를 카운트 한다. 그것은 <literal>PAYMENT</literal>,
|
|
<literal>PAYMENT_STATUS</literal>, <literal>PAYMENT_STATUS_CHANGE</literal> 테이블들에 대한 두 개의 inner
|
|
조인들과 하나의 상관관계 지워진 subselect를 가진 SQL 질의로 변환된다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select count(payment), status.name
|
|
from Payment as payment
|
|
join payment.currentStatus as status
|
|
join payment.statusChanges as statusChange
|
|
where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
|
|
or (
|
|
statusChange.timeStamp = (
|
|
select max(change.timeStamp)
|
|
from PaymentStatusChange change
|
|
where change.payment = payment
|
|
)
|
|
and statusChange.user <> :currentUser
|
|
)
|
|
group by status.name, status.sortOrder
|
|
order by status.sortOrder]]></programlisting>
|
|
|
|
<para>
|
|
만일 내가 <literal>statusChanges</literal> 콜렉션을 set가 아닌 list로 매핑했다면, 그 질의는 작성하기가 훨씬 더
|
|
간단했을 것이다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select count(payment), status.name
|
|
from Payment as payment
|
|
join payment.currentStatus as status
|
|
where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
|
|
or payment.statusChanges[ maxIndex(payment.statusChanges) ].user <> :currentUser
|
|
group by status.name, status.sortOrder
|
|
order by status.sortOrder]]></programlisting>
|
|
|
|
<para>
|
|
다음 질의는 현재의 사용자가 속해 있는 조직의 모든 계정들과 지불되지 않은 지불들을 반환하는데 MS SQL Server
|
|
<literal>isNull()</literal> 함수를 사용한다. 그것은 <literal>ACCOUNT</literal>, <literal>PAYMENT</literal>,
|
|
<literal>PAYMENT_STATUS</literal>, <literal>ACCOUNT_TYPE</literal>, <literal>ORGANIZATION</literal>,
|
|
<literal>ORG_USER</literal> 테이블들에 대한 세 개의 inner 조인들, 하나의 outer 조인, 그리고 하나의 subselect를 가진
|
|
한 개의 SQL 질의로 번역된다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select account, payment
|
|
from Account as account
|
|
left outer join account.payments as payment
|
|
where :currentUser in elements(account.holder.users)
|
|
and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
|
|
order by account.type.sortOrder, account.accountNumber, payment.dueDate]]></programlisting>
|
|
|
|
<para>
|
|
몇몇 데이터베이스들의 경우, 우리는 (상관관계 지워진) subselect를 없앨 필요가 있을 것이다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select account, payment
|
|
from Account as account
|
|
join account.holder.users as user
|
|
left outer join account.payments as payment
|
|
where :currentUser = user
|
|
and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
|
|
order by account.type.sortOrder, account.accountNumber, payment.dueDate]]></programlisting>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="queryhql-bulk" revision="2">
|
|
<title>대량 update와 delete</title>
|
|
|
|
<para>
|
|
HQL은 이제 <literal>update</literal>, <literal>delete</literal> 그리고
|
|
<literal>insert ... select ...</literal> 문장들을 지원한다.
|
|
상세한 것은 <xref linkend="batch-direct"/>를 보라.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 id="queryhql-tipstricks">
|
|
<title>팁들 & 트릭들</title>
|
|
|
|
<para>
|
|
당신은 실제로 질의 결과들을 반환하지 않고서 그것들(질의 결과들)의 개수를 카운트할 수 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[( (Integer) session.iterate("select count(*) from ....").next() ).intValue()]]></programlisting>
|
|
|
|
<para>
|
|
콜렉션의 크기에 따라 결과를 순서(ordering)지우려면, 다음 질의를 사용하라:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select usr.id, usr.name
|
|
from User as usr
|
|
left join usr.messages as msg
|
|
group by usr.id, usr.name
|
|
order by count(msg)]]></programlisting>
|
|
|
|
<para>
|
|
만일 당신의 데이터베이스가 subselect들을 지원할 경우, 당신은 당신의 질의의 where 절 내에 selection 사이즈에 대한 조건을
|
|
위치지울 수 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[from User usr where size(usr.messages) >= 1]]></programlisting>
|
|
|
|
<para>
|
|
만일 당신의 데이터베이스가 subselect를 지원하지 않을 경우, 다음 질의를 사용하라:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select usr.id, usr.name
|
|
from User usr.name
|
|
join usr.messages msg
|
|
group by usr.id, usr.name
|
|
having count(msg) >= 1]]></programlisting>
|
|
|
|
<para>
|
|
이 해결책이 inner 조인 때문에 0개의 메시지를 가진 <literal>User</literal>를 반환할 수 없으므로, 다음 형식이 또한 유용하다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[select usr.id, usr.name
|
|
from User as usr
|
|
left join usr.messages as msg
|
|
group by usr.id, usr.name
|
|
having count(msg) = 0]]></programlisting>
|
|
|
|
<para>
|
|
하나의 JavaBean의 프로퍼티들은 명명된 질의 파라미터들에 바인드될 수 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[Query q = s.createQuery("from foo Foo as foo where foo.name=:name and foo.size=:size");
|
|
q.setProperties(fooBean); // fooBean has getName() and getSize()
|
|
List foos = q.list();]]></programlisting>
|
|
|
|
<para>
|
|
콜렉션들은 필터를 가진 <literal>Query</literal> 인터페이스를 사용하여 쪼매김하는 것이 가능하다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[Query q = s.createFilter( collection, "" ); // the trivial filter
|
|
q.setMaxResults(PAGE_SIZE);
|
|
q.setFirstResult(PAGE_SIZE * pageNumber);
|
|
List page = q.list();]]></programlisting>
|
|
|
|
<para>
|
|
콜렉션 요소들은 질의 필터를 사용하여 순서(ordering)지워지거나 그룹지워질 수 도 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[Collection orderedCollection = s.filter( collection, "order by this.amount" );
|
|
Collection counts = s.filter( collection, "select this.type, count(this) group by this.type" );]]></programlisting>
|
|
|
|
<para>
|
|
당신은 콜렉션을 초기화 하지 않고서 그것(콜렉션)의 크기를 찾을 수 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[( (Integer) session.iterate("select count(*) from ....").next() ).intValue();]]></programlisting>
|
|
|
|
</sect1>
|
|
|
|
</chapter>
|
|
|