mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-03-03 08:19:15 +00:00
git-svn-id: https://svn.jboss.org/repos/hibernate/trunk/Hibernate3/doc@8292 1b8cb986-b30d-0410-93ca-fae66ebed9b2
586 lines
28 KiB
XML
586 lines
28 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<chapter id="querysql" revision="2">
|
|
<title>Native SQL</title>
|
|
|
|
<para>
|
|
당신은 또한 당신의 데이터베이스의 native SQL dialect로 질의들을 표현할 수도 있다. 당신이 오라클의 질의 힌트들 또는
|
|
<literal>CONNECT</literal> 키워드와 같은 데이터베이스 지정적인 특징들을 활용하고자 원할 경우에 이것이 유용하다.
|
|
그것은 또한 직접적인 SQL/JDBC 기반의 어플리케이션으로부터 Hibernate로의 보다 명료한 이전 경로를 제공한다.
|
|
</para>
|
|
|
|
<para>
|
|
Hibernate3은 또한 모든 create, update, delete, load 오퍼레이션들에 대해 (내장 프로시저들을 포함하여) 손으로 작성된 SQL을
|
|
지정하는 것을 당신에게 허용해준다.
|
|
</para>
|
|
|
|
<sect1 id="querysql-creating" revision="3">
|
|
<title><literal>SQLQuery</literal> 사용하기</title>
|
|
|
|
<para>
|
|
native SQL 질의들의 실행은 <literal>SQLQuery</literal> 인터페이스를 통해 제어되며, 그것은
|
|
<literal>Session.createSQLQuery()</literal>을 호출하여 획득된다. 극히 간단한 경우들에서 ,
|
|
우리는 다음 형식을 사용할 수 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[List cats = sess.createSQLQuery("select * from cats")
|
|
.addEntity(Cat.class)
|
|
.list();]]></programlisting>
|
|
|
|
<para>이 질의는 다음을 지정했다:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
SQL 질의 문자열
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
그 질의에 의해 반환되는 엔티티
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
여기서, 결과 셋 컬럼 이름들은 매핑 문서 내에 지정된 컬럼 이름들과 동일한 것으로 가정된다. 이것은 조인 다중 테이블들을 가진
|
|
SQL 질의들에 대해 문제가 될 수 있다. 왜냐하면 동일한 컬럼 이름들이 하나 이상의 테이블 들 내에 나타날 수도 있기 때문이다.
|
|
다음 형식은 컬럼 이름 중복에 대해 취약하지 않다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[List cats = sess.createSQLQuery("select {cat.*} from cats cat")
|
|
.addEntity("cat", Cat.class)
|
|
.list();]]></programlisting>
|
|
|
|
<para>이 질의는 다음을 지정했다:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
Hibernate가 컬럼 alias들을 도입하기 위한, placeholder를 가진, SQL 질의 문자열
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
그 질의에 의해 반환된 엔티티와 그것의 SQL 테이블 alias
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
<literal>addEntity()</literal> 메소드는 SQL 테이블 alias를 반환된 엔티티 클래스와 연관지우고,
|
|
질의 결과 셋의 형태를 결정한다.
|
|
</para>
|
|
|
|
<para>
|
|
<literal>addJoin()</literal> 메소드는 다른 엔티티들과 콜렉션들에 대한 연관들을 로드시키는데 사용될 수 있다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[List cats = sess.createSQLQuery(
|
|
"select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
|
|
)
|
|
.addEntity("cat", Cat.class)
|
|
.addJoin("kitten", "cat.kittens")
|
|
.list();]]></programlisting>
|
|
|
|
<para>
|
|
native SQL 질의는 간단한 스칼라 값을 반환하거나 스칼라들과 엔티티들의 조합을 반환할 수도 있다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[Double max = (Double) sess.createSQLQuery("select max(cat.weight) as maxWeight from cats cat")
|
|
.addScalar("maxWeight", Hibernate.DOUBLE);
|
|
.uniqueResult();]]></programlisting>
|
|
|
|
<para>당신은 당신의 hbm 파일들 내에 결과셋 매핑 정보를 대안저긍로 설명활 수 있고 당신의 질의들을 위해 그것들을
|
|
사용할 수 있다.</para>
|
|
|
|
<programlisting><![CDATA[List cats = sess.createSQLQuery(
|
|
"select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
|
|
)
|
|
.setResultSetMapping("catAndKitten")
|
|
.list();]]></programlisting>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="querysql-aliasreferences">
|
|
<title>Alias 참조와 프로퍼티 참조</title>
|
|
|
|
<para>
|
|
위에서 사용된 <literal>{cat.*}</literal> 표기는 "모든 프로퍼티"에 대한 약어이다. 다른 방법으로, 당신은 명시적으로 컬럼들을
|
|
리스트할 수 있지만, 심지어 이 경우 조차도 우리는 Hibernate로 하여금 각각의 프로퍼티에 대해 SQL 컬럼 alias들을 끼워넣도록 해야 한다.
|
|
컬럼 alias에 대한 placeholder는 테이블 alias 수식어가 붙은 프로퍼티 이름이다. 다음 예제에서, 우리는 매핑 메타데이터에 선언된
|
|
것에 대해 다른 테이블 (<literal>cat_log</literal>)로부터 <literal>Cat</literal>들을 검색한다. 우리는 심지어 우리가
|
|
좋아할 경우 where 절 속에 프로퍼티 alias들을 사용할 수도 있음을 주목하라.
|
|
</para>
|
|
<para>
|
|
The <literal>{}</literal>-syntax is <emphasis>not</emphasis> required for named queries.
|
|
See <xref linkend="querysql-namedqueries"/>
|
|
</para>
|
|
|
|
<programlisting><![CDATA[String sql = "select cat.originalId as {cat.id}, " +
|
|
"cat.mateid as {cat.mate}, cat.sex as {cat.sex}, " +
|
|
"cat.weight*10 as {cat.weight}, cat.name as {cat.name} " +
|
|
"from cat_log cat where {cat.mate} = :catId"
|
|
|
|
List loggedCats = sess.createSQLQuery(sql)
|
|
.addEntity("cat", Cat.class)
|
|
.setLong("catId", catId)
|
|
.list();]]></programlisting>
|
|
|
|
<para>
|
|
<emphasis>노트:</emphasis> 만일 당신이 각각의 프로퍼티를 명시적으로 리스트할 경우, 당신은 그 클래스와
|
|
<emphasis>그것의 서브클래스들</emphasis>의 모든 프로퍼티들을 포함해야 한다!
|
|
</para>
|
|
<para>
|
|
다음 테이블은 alias injection을 사용하는 다른 가능성들을 보여준다. 노트 : 결과 내에서 alias 이름들이 예제들이며, 각각의 alias는
|
|
사용될 시에 하나의 유일한 그리고 가능한 다른 이름을 가질 것이다.
|
|
</para>
|
|
|
|
<table frame="topbot" id="aliasinjection-summary">
|
|
<title>Alias injection 이름들</title>
|
|
|
|
<tgroup cols="4">
|
|
<colspec colwidth="1*"/>
|
|
|
|
<colspec colwidth="1*"/>
|
|
|
|
<colspec colwidth="2.5*"/>
|
|
|
|
<thead>
|
|
<row>
|
|
<entry>설명</entry>
|
|
<entry>구문</entry>
|
|
<entry>예제</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry>간단한 프로퍼티</entry>
|
|
<entry><literal>{[aliasname].[propertyname]</literal></entry>
|
|
<entry><literal>A_NAME as {item.name}</literal></entry>
|
|
</row>
|
|
<row>
|
|
<entry>composite 프로퍼티</entry>
|
|
<entry><literal>{[aliasname].[componentname].[propertyname]}</literal></entry>
|
|
<entry><literal>CURRENCY as {item.amount.currency}, VALUE as {item.amount.value}</literal></entry>
|
|
</row>
|
|
<row>
|
|
<entry>엔티티의 판별자(Discriminator)</entry>
|
|
<entry><literal>{[aliasname].class}</literal></entry>
|
|
<entry><literal>DISC as {item.class}</literal></entry>
|
|
</row>
|
|
<row>
|
|
<entry>엔티티의 모든 프로퍼티들</entry>
|
|
<entry><literal>{[aliasname].*}</literal></entry>
|
|
<entry><literal>{item.*}</literal></entry>
|
|
</row>
|
|
<row>
|
|
<entry>콜렉션 키</entry>
|
|
<entry><literal>{[aliasname].key}</literal></entry>
|
|
<entry><literal>ORGID as {coll.key}</literal></entry>
|
|
</row>
|
|
<row>
|
|
<entry>콜렉션의 id</entry>
|
|
<entry><literal>{[aliasname].id}</literal></entry>
|
|
<entry><literal>EMPID as {coll.id}</literal></entry>
|
|
</row>
|
|
<row>
|
|
<entry>콜렉션의 요소</entry>
|
|
<entry><literal>{[aliasname].element}</literal></entry>
|
|
<entry><literal>XID as {coll.element}</literal></entry>
|
|
<entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry>콜렉션 내에 있는 요소의 프로퍼티</entry>
|
|
<entry><literal>{[aliasname].element.[propertyname]}</literal></entry>
|
|
<entry><literal>NAME as {coll.element.name}</literal></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry>콜렉션 내에 있는 요소의 모든 프로퍼티들</entry>
|
|
<entry><literal>{[aliasname].element.*}</literal></entry>
|
|
<entry><literal>{coll.element.*}</literal></entry>
|
|
</row>
|
|
<row>
|
|
<entry>콜렉션의 모든 프로퍼티들</entry>
|
|
<entry><literal>{[aliasname].*}</literal></entry>
|
|
<entry><literal>{coll.*}</literal></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="querysql-namedqueries" revision="3">
|
|
<title>명명된 SQL 질의들</title>
|
|
|
|
<para>
|
|
명명된 SQL 질의들은 HQL 질의와 동일한 방법으로 매핑 문서 속에 정의될 수 있고 정확하게 호출될 수도 있다. 이 경우에, 우리는
|
|
<literal>addEntity()</literal> 호출을 필요로 하지 <emphasis>않는다</emphasis>.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<sql-query name="persons">
|
|
<return alias="person" class="eg.Person"/>
|
|
SELECT person.NAME AS {person.name},
|
|
person.AGE AS {person.age},
|
|
person.SEX AS {person.sex}
|
|
FROM PERSON person
|
|
WHERE person.NAME LIKE :namePattern
|
|
</sql-query>]]></programlisting>
|
|
|
|
<programlisting><![CDATA[List people = sess.getNamedQuery("persons")
|
|
.setString("namePattern", namePattern)
|
|
.setMaxResults(50)
|
|
.list();]]></programlisting>
|
|
<para>
|
|
The <literal><return-join></literal> 요소와 <literal><load-collection></literal>
|
|
요소는 연관들을 조인시키고 콜렉션들을 각각 초기화 시키는 질의들을 정의하는데 사용된다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<sql-query name="personsWith">
|
|
<return alias="person" class="eg.Person"/>
|
|
<return-join alias="address" property="person.mailingAddress"/>
|
|
SELECT person.NAME AS {person.name},
|
|
person.AGE AS {person.age},
|
|
person.SEX AS {person.sex},
|
|
adddress.STREET AS {address.street},
|
|
adddress.CITY AS {address.city},
|
|
adddress.STATE AS {address.state},
|
|
adddress.ZIP AS {address.zip}
|
|
FROM PERSON person
|
|
JOIN ADDRESS adddress
|
|
ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
|
|
WHERE person.NAME LIKE :namePattern
|
|
</sql-query>]]></programlisting>
|
|
|
|
<para>
|
|
명명된 SQL 질의는 스칼라 값을 반환할수도 있다. 당신은 <literal><return-scalar></literal> 요소를 사용하여
|
|
컬럼 alias와 Hibernate 타입을 선언해야 한다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<sql-query name="mySqlQuery">
|
|
<return-scalar column="name" type="string"/>
|
|
<return-scalar column="age" type="long"/>
|
|
SELECT p.NAME AS name,
|
|
p.AGE AS age,
|
|
FROM PERSON p WHERE p.NAME LIKE 'Hiber%'
|
|
</sql-query>]]></programlisting>
|
|
|
|
<para>당신은 여러 개의 명명된 질의들을 가로질러 재사용하거나 <literal>setResultSetMapping()</literal> API를 통해 결과셋
|
|
매핑정보들을 재사용하기 위해 <literal><resultset></literal> 요소 속에 결과셋 매핑 정보들을 구체화 시킬 수 있다.</para>
|
|
|
|
<programlisting><![CDATA[<resultset name="personAddress">
|
|
<return alias="person" class="eg.Person"/>
|
|
<return-join alias="address" property="person.mailingAddress"/>
|
|
</resultset>
|
|
|
|
<sql-query name="personsWith" resultset-ref="personAddress">
|
|
SELECT person.NAME AS {person.name},
|
|
person.AGE AS {person.age},
|
|
person.SEX AS {person.sex},
|
|
adddress.STREET AS {address.street},
|
|
adddress.CITY AS {address.city},
|
|
adddress.STATE AS {address.state},
|
|
adddress.ZIP AS {address.zip}
|
|
FROM PERSON person
|
|
JOIN ADDRESS adddress
|
|
ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
|
|
WHERE person.NAME LIKE :namePattern
|
|
</sql-query>]]></programlisting>
|
|
|
|
<sect2 id="propertyresults">
|
|
<title>명시적으로 column/alias 이름들을 지정하는데 return-property 사용하기</title>
|
|
|
|
<para>
|
|
Hibernate로 하여금 그것 자신의 alias들을 끼워넣도록 하기 위해 <literal>{}</literal>-구문을 사용하는 것 대신에,
|
|
<literal><return-property></literal>로서 당신은 사용할 컬럼 alias들이 무엇인지를 Hibernate에게 명시적으로
|
|
알려줄 수 있다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<sql-query name="mySqlQuery">
|
|
<return alias="person" class="eg.Person">
|
|
<return-property name="name" column="myName"/>
|
|
<return-property name="age" column="myAge"/>
|
|
<return-property name="sex" column="mySex"/>
|
|
</return>
|
|
SELECT person.NAME AS myName,
|
|
person.AGE AS myAge,
|
|
person.SEX AS mySex,
|
|
FROM PERSON person WHERE person.NAME LIKE :name
|
|
</sql-query>
|
|
]]></programlisting>
|
|
|
|
<para>
|
|
<literal><return-property></literal>는 또한 다중 컬럼들에 대해 동작한다. 이것은 다중-컬럼 프로퍼티들에
|
|
대한 fine grained 제어를 허용할 수 없는 <literal>{}</literal>-구문을 가진 제약을 해결해준다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<sql-query name="organizationCurrentEmployments">
|
|
<return alias="emp" class="Employment">
|
|
<return-property name="salary">
|
|
<return-column name="VALUE"/>
|
|
<return-column name="CURRENCY"/>
|
|
</return-property>
|
|
<return-property name="endDate" column="myEndDate"/>
|
|
</return>
|
|
SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer},
|
|
STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
|
|
REGIONCODE as {emp.regionCode}, EID AS {emp.id}, VALUE, CURRENCY
|
|
FROM EMPLOYMENT
|
|
WHERE EMPLOYER = :id AND ENDDATE IS NULL
|
|
ORDER BY STARTDATE ASC
|
|
</sql-query>]]></programlisting>
|
|
|
|
<para>
|
|
이 예제에서 우리는 끼워넣기(injection)를 위해 <literal>{}</literal>-구문과 함께 <literal><return-property></literal>를
|
|
사용했음을 주목하라. 사용자들이 컬럼과 프로퍼티들을 참조하고자 원하는 방법을 선택하는 것을 사용자들에게 허용해줌으로써.
|
|
</para>
|
|
|
|
<para>
|
|
만일 당신의 매핑이 한 개의 판별자(discriminator )를 가질 경우 당신은 판별자 컬럼을 지정하는데
|
|
<literal><return-discriminator></literal>를 사용해야 한다.
|
|
</para>
|
|
</sect2>
|
|
|
|
<sect2 id="sp_query">
|
|
<title>질의를 위한 내장 프로시저 사용하기</title>
|
|
|
|
<para>
|
|
Hibernate 3은 내장 프로시저들을 통한 질의들에 대한 지원을 도입한다. 내장 프로시저들은 Hibernate와 동작하는 것이
|
|
가능하도록 첫 번째 출력-파라미터로서 한 개의 결과셋을 반환해야 한다. Oracle9 이상의 버전에서 그런 내장 프로시저에
|
|
대한 예제는 다음과 같다:
|
|
</para>
|
|
<programlisting><![CDATA[CREATE OR REPLACE FUNCTION selectAllEmployments
|
|
RETURN SYS_REFCURSOR
|
|
AS
|
|
st_cursor SYS_REFCURSOR;
|
|
BEGIN
|
|
OPEN st_cursor FOR
|
|
SELECT EMPLOYEE, EMPLOYER,
|
|
STARTDATE, ENDDATE,
|
|
REGIONCODE, EID, VALUE, CURRENCY
|
|
FROM EMPLOYMENT;
|
|
RETURN st_cursor;
|
|
END;]]></programlisting>
|
|
|
|
<para>
|
|
Hibernate에서 이 질의를 사용하기 위해 당신은 하나의 명명된 질의(a named query)를 통해 그것을 매핑할 필요가 있다.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<sql-query name="selectAllEmployees_SP" callable="true">
|
|
<return alias="emp" class="Employment">
|
|
<return-property name="employee" column="EMPLOYEE"/>
|
|
<return-property name="employer" column="EMPLOYER"/>
|
|
<return-property name="startDate" column="STARTDATE"/>
|
|
<return-property name="endDate" column="ENDDATE"/>
|
|
<return-property name="regionCode" column="REGIONCODE"/>
|
|
<return-property name="id" column="EID"/>
|
|
<return-property name="salary">
|
|
<return-column name="VALUE"/>
|
|
<return-column name="CURRENCY"/>
|
|
</return-property>
|
|
</return>
|
|
{ ? = call selectAllEmployments() }
|
|
</sql-query>]]></programlisting>
|
|
|
|
<para>
|
|
내장 프로시저들은 현재 스칼라들과 엔티티들 만을 반환함을 주목하라. <literal><return-join></literal>과
|
|
<literal><load-collection></literal>은 지원되지 않는다.
|
|
</para>
|
|
|
|
<sect3 id="querysql-limits-storedprocedures">
|
|
<title>내장 프로시저들을 사용하는 규칙들/제약들</title>
|
|
|
|
<para>
|
|
Hibernate에서 내장 프로시저들을 사용하기 위해서 프로시저들은 다음 몇몇 규칙들을 따라야 한다. 만일 그것들이 그들 규칙들을
|
|
따르지 않을 경우 그것들은 Hibernate와 함께 사용 불가능하다. 만일 당신이 여전히 이들 프로시저들을 사용하고자 원할 경우,
|
|
당신은 <literal>session.connection()</literal>을 통해 그것들을 실행시켜야 한다. 데이터베이스 벤더들이 다른 내장
|
|
프로시저 의미론/구문을 갖고 있기 때문에, 규칙들은 각각의 데이터베이스에 따라 차이가 난다.
|
|
</para>
|
|
|
|
<para>
|
|
내장 프로시저 질의들은 <literal>setFirstResult()/setMaxResults()</literal>로서 쪽매김 될 수 없다.
|
|
</para>
|
|
|
|
<para>
|
|
Oracle의 경우 다음 규칙들이 적용된다:
|
|
</para>
|
|
|
|
<itemizedlist spacing="compact">
|
|
<listitem>
|
|
<para>
|
|
프로시저는 한 개의 결과 셋을 반환해야 한다. 이것은 Oracle 9 또는 10에서 한 개의 <literal>SYS_REFCURSOR</literal>를
|
|
반환함으로써 행해진다. Oracle에서 당신은 한 개의 <literal>REF CURSOR</literal> 타입을 정의할 필요가 있다.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
권장되는 형식은 <literal>{ ? = call procName(<parameters>) }</literal> 또는
|
|
<literal>{ ? = call procName }</literal>이다.(이것은 Hibernate 규칙이라기 보다는 Oracle 규칙이다.)
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
Sybase 또는 MS SQL server의 경우 다음 규칙들이 적용된다:
|
|
</para>
|
|
|
|
<itemizedlist spacing="compact">
|
|
<listitem>
|
|
<para>
|
|
프로시저는 한 개의 결과 셋을 반환해야 한다. 이들 서버들이 여러 개의 결과셋들과 업데이트 카운트들을 반환 할수 있다/할 것이이므로,
|
|
Hibernate는 결과들을 반복 순환할 것이고 그것의 반환 값으로서 하나의 결과 셋인 첫 번째 결과를 취할 것이다. 그 밖의 모든 것은
|
|
폐기될 것이다.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
만일 당신이 당신의 프로시저 내에 <literal>SET NOCOUNT ON</literal>을 이용 가능하게 할 수 있다면 그것은 아마
|
|
보다 효율적이게 될 것이지만 이것은 필요 조건이 아니다.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</sect3>
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="querysql-cud">
|
|
<title>create, update 그리고 delete를 위한 맞춤형 SQL</title>
|
|
|
|
<para>
|
|
Hibernate3는 create, update, delete 오퍼레이션들을 위한 맞춤형 문장들을 사용할 수 있다. Hibernate에서 클래스와 콜렉션
|
|
영속자들은 구성 시에 생성된 문자열들의 집합(insertsql, deletesql, updatesql 등)을 이미 포함하고 있다.
|
|
<literal><sql-insert></literal>, <literal><sql-delete></literal>,
|
|
<literal><sql-update></literal> 매핑 태그들은 이들 문자열들을 오버라이드 시킨다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<class name="Person">
|
|
<id name="id">
|
|
<generator class="increment"/>
|
|
</id>
|
|
<property name="name" not-null="true"/>
|
|
<sql-insert>INSERT INTO PERSON (NAME, ID) VALUES ( UPPER(?), ? )</sql-insert>
|
|
<sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE ID=?</sql-update>
|
|
<sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete>
|
|
</class>]]></programlisting>
|
|
|
|
<para>
|
|
SQL이 당신의 데이터베이스 내에서 직접 실행되어서, 당신이 좋아하는 임의의 dialect를 사용하는 것이 자유롭다. 만일 당신이 데이터베이스
|
|
지정적인 SQL을 사용할 경우 이것은 물론 당신의 매핑의 이식성을 감소시킬 것이다.
|
|
</para>
|
|
|
|
<para>
|
|
만일 <literal>callable</literal> 속성이 설정되면 내장 프로시저들이 지원된다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<class name="Person">
|
|
<id name="id">
|
|
<generator class="increment"/>
|
|
</id>
|
|
<property name="name" not-null="true"/>
|
|
<sql-insert callable="true">{call createPerson (?, ?)}</sql-insert>
|
|
<sql-delete callable="true">{? = call deletePerson (?)}</sql-delete>
|
|
<sql-update callable="true">{? = call updatePerson (?, ?)}</sql-update>
|
|
</class>]]></programlisting>
|
|
|
|
<para>
|
|
위치 파라미터들은 Hibernate가 그것들을 기대하는 것과 같은 순서가 되어야 하므로, 위치 파라미터들의 순서는 현재 절대적으로 중요하다.
|
|
</para>
|
|
|
|
<para>
|
|
당신은 <literal>org.hiberate.persister.entity</literal> 레벨로 디버그 로깅을 사용 가능하게 함으로써 예상된 순서를 볼 수
|
|
있다. 이 레벨을 이용 가능하게 하면 Hibernate는 엔티티들을 생성시키고, 업데이트하고, 삭제하는데 사용되는 정적인 SQL을 출력할 것이다.
|
|
(예상되는 결과를 보려면, Hibernate 생성된 정적인 sql을 오버라이드 시키게 매핑 파일들 속에 당신의 맞춤형 SQL을 포함시키지 않도록 염두에
|
|
두라.)
|
|
</para>
|
|
|
|
<para>
|
|
Hibernate가 문장의 성공을 위해 몇몇 실행 시 체크들을 행하므로, 내장 프로시저들은 대부분의 경우들(읽기:다른 경우들 보다 그것을 더 잘
|
|
행한다)에서 insert되고/업데이트되고/삭제된 행들의 개수를 반환하는데 필요하다. Hibernate는 항상 CUD 오퍼레이션들에 대한 숫자
|
|
출력 파라미터로서 첫 번째 문장 파라미터를 등록시킨다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2)
|
|
RETURN NUMBER IS
|
|
BEGIN
|
|
|
|
update PERSON
|
|
set
|
|
NAME = uname,
|
|
where
|
|
ID = uid;
|
|
|
|
return SQL%ROWCOUNT;
|
|
|
|
END updatePerson;]]></programlisting>
|
|
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="querysql-load">
|
|
<title>로딩을 위한 맞춤형 SQL</title>
|
|
|
|
<para>
|
|
당신은 또한 엔티티 로딩을 위한 당신 자신의 SQL (또는 HQL)을 선언할 수도 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<sql-query name="person">
|
|
<return alias="pers" class="Person" lock-mode="upgrade"/>
|
|
SELECT NAME AS {pers.name}, ID AS {pers.id}
|
|
FROM PERSON
|
|
WHERE ID=?
|
|
FOR UPDATE
|
|
</sql-query>]]></programlisting>
|
|
|
|
<para>
|
|
이것은 앞서 논의했듯이 단지 명명된 질의 선언이다. 당신은 class 매핑 속에 이 명명된 질의를 참조할 수 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<class name="Person">
|
|
<id name="id">
|
|
<generator class="increment"/>
|
|
</id>
|
|
<property name="name" not-null="true"/>
|
|
<loader query-ref="person"/>
|
|
</class>]]></programlisting>
|
|
|
|
<para>
|
|
이것은 심지어 내장 프로시저들에 동작한다.
|
|
</para>
|
|
|
|
<para>
|
|
당신은 콜렉션 로딩을 위한 한 개의 질의를 정의할 수도 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<set name="employments" inverse="true">
|
|
<key/>
|
|
<one-to-many class="Employment"/>
|
|
<loader query-ref="employments"/>
|
|
</set>]]></programlisting>
|
|
|
|
<programlisting><![CDATA[<sql-query name="employments">
|
|
<load-collection alias="emp" role="Person.employments"/>
|
|
SELECT {emp.*}
|
|
FROM EMPLOYMENT emp
|
|
WHERE EMPLOYER = :id
|
|
ORDER BY STARTDATE ASC, EMPLOYEE ASC
|
|
</sql-query>]]></programlisting>
|
|
|
|
<para>
|
|
당신은 심지어 조인 페칭에 의해 하나의 콜렉션을 로드시키는 하나의 엔티티를 정의할 수 있다:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<sql-query name="person">
|
|
<return alias="pers" class="Person"/>
|
|
<return-join alias="emp" property="pers.employments"/>
|
|
SELECT NAME AS {pers.*}, {emp.*}
|
|
FROM PERSON pers
|
|
LEFT OUTER JOIN EMPLOYMENT emp
|
|
ON pers.ID = emp.PERSON_ID
|
|
WHERE ID=?
|
|
</sql-query>]]></programlisting>
|
|
|
|
</sect1>
|
|
|
|
</chapter> |