3.1 はじめに
もう 1 つ話したい便利な点は、NativeQueryです。すでにご存知のとおり、NativeQuery を使用すると、ネイティブ SQL でクエリを作成できます。ただし、さらに興味深いのは、クエリ結果を取得するときにクラス マッピングを使用する必要がないことです。
むしろ例を示したいと思います。
List<Object[]> persons = session.createNativeQuery("SELECT * FROM Person").list();
この例では、クエリ結果の行に一致するクラスを渡さず、代わりに Object オブジェクトの配列を使用します。
これは、テーブル内のいくつかの列だけを選択する場合に便利です。例:
List<Object[]> persons = session.createNativeQuery("SELECT id, name FROM Person").list();
for(Object[] person : persons) {
Number id = (Number) person[0];
String name = (String) person[1];
}
これは、ResultSet オブジェクトを取得してその行からデータを読み取るときの JDBC のアプローチに似ています。
ただし、Hibernate では、これの信頼性を高めるためのさまざまな方法が提供されています。たとえば、減算する列のタイプを指定できます。例:
Query<Object[]> query = session.createNativeQuery("SELECT id, name FROM Person");
query.addScalar("id", StandardBasicTypes.LONG);
query.addScalar("name", StandardBasicTypes.STRING);
List<Object[]> persons = query.list();
for(Object[] person : persons) {
Long id = (Long) person[0];
String name = (String) person[1];
}
3.2 エンティティのマッピング
NativeQueryの結果を解析するときに Hibernate が使用するクラスを明示的に指定することもできます。これはさまざまな方法で実行できます。
Query<Person> query = session.createNativeQuery("SELECT * FROM Person")
.addEntity(Person.class);
.list();
そしてもちろん、あなたが知っている古き良き形式:
Query<Person> query = session.createNativeQuery("SELECT * FROM Person", Person.class).list();
1 つ目のアプローチはネイティブ Hibernate アプローチで、2 つ目は JPA アプローチです。JPA アプローチは、Hibernate が長年存在していた後に考案された標準であるため、より便利で簡潔です。そして Hibernate は進化し、古いバージョンとの互換性を維持するために古いアプローチをサポートする必要がありました。
ちなみに、Hibernate ではそのアプローチのおかげで、1 つのクラスをクエリ結果マッピングに接続するのではなく、複数のクラスを接続することができます。例:
List<Phone> results = session.createNativeQuery(
"SELECT {ph.*}, {pr.*}" +
"FROM Phone ph" +
"JOIN Person pr ON ph.person_id = pr.id")
.addEntity("ph", Phone.class)
.addJoin("pr", "ph.person")
.list();
for (Phone. phone : results) {
assertNotNull( phone.getPerson().getName() );
}
NativeQueryを使用したこのアプローチを使用すると、データベースからのデータの選択を高速化できます。一部の列が必要ないことがわかっている場合は、リクエストでそれらを省略できます。
Hibernate がCacheまたはLazyLoadingメカニズムを使用したい場合でも、すべての子エンティティを一度にロードすることもできます。さらに、子エンティティにはデータベース内に多数の列がある場合があり、そのうちの一部のみを選択できます。
3.3 DTO マッピング
Hibernate では、結果のマッピングに非エンティティ クラスを使用することもできます。注釈がなく、どのテーブルにもマップされていないクラス。
例:
public class PersonSummaryDTO {
private Number id;
private String name;
public Number getId() {
return id;
}
public void setId(Number id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
List<PersonSummaryDTO> dtos = session.createNativeQuery(
"SELECT p.id as \"id\", p.name as \"name\" FROM Person p")
.setResultTransformer(Transformers.aliasToBean(PersonSummaryDTO.class) )
.list();
PersonsummaryDTO クラスには注釈がないため、SQL クエリ内の列の名前は、PersonsummaryDTO クラスのフィールドの名前と正確に一致する必要があります。
これは、アプリケーションが読み取り専用モードでのみ接続されている外部データベースからデータを読み取る場合に非常に便利です。つまり、50 を超える列を持つテーブルへのアクセスが許可され、選択を高速化するためにデータが非正規化形式で保存されます。
あるいは、誰かがクラス階層を 1 つのテーブルに保存することに決め、5 年間でこのテーブルが悪魔に足を折られるほど大きくなったとします。このテーブルからいくつかの列 (ID とユーザー名) を選択し、クライアントに提供する必要があります。
理解できたと思いますが、このトピックについてさらに詳しく知りたい場合は、次のリンクで詳細を読むことができます。