※当サイトの記事には、広告・プロモーションが含まれます。

JPA(Java Persistence API)でnativeQueryのクエリの結果をマッピングしたいけど...

nazology.net

⇧ Oh, my gosh...

そもそもnativeQueryの結果をマッピングできるのか?

調べた限りでは、

www.sakatakoichi.com

zenn.dev

⇧ 上記サイト様が参考になりそうです。

JPAでnativeQueryのクエリの結果をマッピングしたいけど...

ただ、結局のところ、SQL毎にエンティティを作ってられないと思うので、nativeQueryの結果をエンティティやDTOに変換するのを手動でやらざるを得ないかと。

どういうことかと言うと、戻り値は同じでもSQLの条件が微妙に異なる場合に、SqlResultSetMappingとNamedNativeQueryを使う方法だと、10個のSQL文があると10個のエンティティを用意しないといけなくなりますと。

そこで、クエリの戻り値がList<Object[]>になるのを許容して、手動でマッピングするという選択肢もあるのかなと。

PostgreSQLで以下のようなテーブルを用意したとして、

create table public.shikoku_ohenro (
  id serial not null
  , name_fudasyo character varying(20) not null
  , kana_name_fudasyo character varying(50) not null
  , rome_name_fudasyo character varying(50) not null
  , name_temple character varying(20) not null
  , kana_name_temple character varying(50) not null
  , rome_name_temple character varying(50) not null
  , prefectures_id integer not null
  , created timestamp(6) with time zone default CURRENT_TIMESTAMP
  , updated timestamp(6) with time zone
  , is_deleted boolean default false
  , primary key (id)
);    
create table public.prefectures (
  id integer not null
  , name_prefecture character varying(20) not null
  , kana_name_prefecture character varying(50) not null
  , rome_name_prefecture character varying(50) not null
  , name_prefectural_capital character varying(20) not null
  , kana_name_prefectural_capital character varying(50) not null
  , rome_name_prefectural_capital character varying(50) not null
  , area_id integer not null
  , created timestamp(6) with time zone default CURRENT_TIMESTAMP
  , updated timestamp(6) with time zone
  , is_deleted boolean default false
  , primary key (id)
);    

データをINSERTしておく。

-- 都道府県データ
INSERT INTO prefectures (id, name_prefecture, kana_name_prefecture, rome_name_prefecture, name_prefectural_capital, kana_name_prefectural_capital, rome_name_prefectural_capital, area_id)
 VALUES(1,'北海道', 'ほっかいどう', 'hokkaido','札幌', 'さっぽろ', 'sapporo', 1)
 ,(2,'青森県', 'あおもりけん', 'aomoriken','青森', 'あおもり', 'aomori', 2)
 ,(3,'岩手県', 'いわてけん', 'iwateken','盛岡', 'もりおか', 'morioka', 2)
 ,(4,'宮城県', 'みやぎけん', 'miyagiken','仙台', 'せんだい', 'sendai', 2)
 ,(5,'秋田県', 'あきたけん', 'akitaken','秋田', 'あきた', 'akita', 2)
 ,(6,'山形県', 'やまがたけん', 'yamagataken','山形', 'やまがた', 'yamagata', 2)
 ,(7,'福島県', 'ふくしまけん', 'fukushimaken','福島', 'ふくしま', 'fukushima', 2)
 ,(8,'茨城県', 'いばらきけん', 'ibarakiken','水戸', 'みと', 'mito', 3)
 ,(9,'栃木県', 'とちぎけん', 'tochigiken','宇都宮', 'うつのみや', 'utsunomiya', 3)
 ,(10,'群馬県', 'ぐんまけん', 'gunmaken','前橋', 'まえばし', 'maebashi', 3)
 ,(11,'埼玉県', 'さいたまけん', 'saitamaken','さいたま', 'さいたま', 'saitama', 3)
 ,(12,'千葉県', 'ちばけん', 'chibaken','千葉', 'ちば', 'chiba', 3)
 ,(13,'東京都', 'とうきょうと', 'tokyoto','新宿', 'しんじゅく', 'shinjyuku', 3)
 ,(14,'神奈川県', 'かながわけん', 'kanagawaken','横浜', 'よこはま', 'yokohama', 3)
 ,(15,'新潟県', 'にいがたけん', 'nigataken','新潟', 'にいがた', 'niigata', 4)
 ,(16,'富山県', 'とやまけん', 'toyamaken','富山', 'とやま', 'toyama', 4)
 ,(17,'石川県', 'いしかわけん', 'ishikawaken','金沢', 'かなざわ', 'kanazawa', 4)
 ,(18,'福井県', 'ふくいけん', 'fukuiken','福井', 'ふくい', 'fukui', 4)
 ,(19,'山梨県', 'やまなしけん', 'yamanashiken','甲府', 'こうふ', 'koufu', 4)
 ,(20,'長野県', 'ながのけん', 'naganoken','長野', 'ながの', 'nagano', 4)
 ,(21,'岐阜県', 'ぎふけん', 'gifuken','岐阜', 'ぎふ', 'gifu', 4)
 ,(22,'静岡県', 'しずおかけん', 'shizuokaken','静岡', 'しずおか', 'shizuoka', 4)
 ,(23,'愛知県', 'あいちけん', 'aichiken','名古屋', 'なごや', 'nagoya', 4)
 ,(24,'三重県', 'みえけん', 'mieken','津', 'つ', 'tsu', 5)
 ,(25,'滋賀県', 'しがけん', 'shigaken','大津', 'おおつ', 'ootsu', 5)
 ,(26,'京都府', 'きょうとふ', 'kyotofu','京都', 'きょうと', 'kyoto', 5)
 ,(27,'大阪府', 'おおさかふ', 'oosakafu','大阪', 'おおさか', 'oosaka', 5)
 ,(28,'兵庫県', 'ひょうごけん', 'hyogoken','神戸', 'こうべ', 'koube', 5)
 ,(29,'奈良県', 'ならけん', 'naraken','奈良', 'なら', 'nara', 5)
 ,(30,'和歌山県', 'わかやまけん', 'wakayamaken','和歌山', 'わかやま', 'wakayama', 5)
 ,(31,'鳥取県', 'とっとりけん', 'tottoriken','鳥取', 'とっとり', 'tottori', 6)
 ,(32,'島根県', 'しまねけん', 'shimaneken','松江', 'まつえ', 'matsue', 6)
 ,(33,'岡山県', 'おかやまけん', 'okayamaken','岡山', 'おかやま', 'okayama', 6)
 ,(34,'広島県', 'ひろしまけん', 'hiroshimaken','広島', 'ひろしま', 'hiroshima', 6)
 ,(35,'山口県', 'やまぐちけん', 'yamaguchiken','山口', 'やまぐち', 'yamaguchi', 6)
 ,(36,'徳島県', 'とくしまけん', 'tokushimaken','徳島', 'とくしま', 'tokushima', 6)
 ,(37,'香川県', 'かがわけん', 'kagawaken','高松', 'たかまつ', 'takamatsu', 6)
 ,(38,'愛媛県', 'えひめけん', 'ehimeken','松山', 'まつやま', 'matsuyama', 6)
 ,(39,'高知県', 'こうちけん', 'kouchiken','高知', 'こうち', 'kouchi', 6)
 ,(40,'福岡県', 'ふくおかけん', 'fukuokaken','福岡', 'ふくおか', 'fukuoka', 7)
 ,(41,'佐賀県', 'さがけん', 'sagaken','佐賀', 'さが', 'saga', 7)
 ,(42,'長崎県', 'ながさきけん', 'nagasakiken','長崎', 'ながさき', 'nagasaki', 7)
 ,(43,'熊本県', 'くまもとけん', 'kumamotoken','熊本', 'くまもと', 'kumamoto', 7)
 ,(44,'大分県', 'おおいたけん', 'ooitaken','大分', 'おおいた', 'ooita', 7)
 ,(45,'宮崎県', 'みやざきけん', 'miyazakiken','宮崎', 'みやざき', 'miyazaki', 7)
 ,(46,'鹿児島県', 'かごしまけん', 'kagoshimaken','鹿児島', 'かごしま', 'kagoshima', 7)
 ,(47,'沖縄県', 'おきなわけん', 'okinawaken','那覇', 'なは', 'naha', 7);    
-- お遍路データ
INSERT INTO shikoku_ohenro (id, name_fudasyo, kana_name_fudasyo, rome_name_fudasyo, name_temple, kana_name_temple, rome_name_temple, prefectures_id)
 VALUES(1, '第1番札所','だいいちばんふだしょ', 'daiichibanfudasyo', '霊山寺', 'りょうぜんじ', 'ryozenji', 36)
 ,(2, '第2番札所','だいにばんふだしょ', 'dainibanfudasyo', '極楽寺', 'ごくらくじ', 'gokurakuji', 36)
 ,(3, '第3番札所','だいさんばんふだしょ', 'daisanbanfudasyo', '金泉寺', 'こんせんじ', 'konsenji', 36)
 ,(4, '第4番札所','だいよんばんふだしょ', 'daiyonbanfudasyo', '大日寺', 'だいにちじ', 'dainichiji', 36)
 ,(5, '第5番札所','だいごばんふだしょ', 'daiigobanfudasyo', '地蔵寺', 'じぞうじ', 'jizouji', 36)
 ,(6, '第6番札所','だいろくばんふだしょ', 'dairokubanfudasyo','安楽寺', 'あんらくじ', 'anrakuji', 36)
 ,(7, '第7番札所','だいななばんふだしょ', 'dainanabanfudasyo','十楽寺', 'じゅうらくじ', 'jyurakuji', 36)
 ,(8, '第8番札所','だいはちばんふだしょ', 'daihachibanfudasyo','熊谷寺', 'くまだにじ ', 'kumadaniji', 36)
 ,(9, '第9番札所','だいきゅうばんふだしょ', 'daikyubanfudasyo','法輪寺', 'ほうりんじ', 'hourinji', 36)
 ,(10,'第10番札所','だいじゅうばんふだしょ', 'daijyubanbanfudasyo','切幡寺', 'きりはたじ', 'kiriharadai', 36)
 ,(11,'第11番札所','だいじゅういちばんふだしょ', 'daijyuichibanfudasyo', '藤井寺', 'ふじいでら', 'fujiidera', 36)
 ,(12,'第12番札所','だいじゅうにばんふだしょ', 'daijyuuibanfudasyo','焼山寺', 'しょうざんじ', 'syouzanji', 36)
 ,(13,'第13番札所','だいじゅうさんばんふだしょ', 'daijyusanbanfudasyo','大日寺', 'だいにちじ', 'dainichiji', 36)
 ,(14,'第14番札所','だいじゅうよんばんふだしょ', 'daijyuyonbanfudasyo','常楽寺', 'じょうらくじ', 'jyourakuji', 36)
 ,(15,'第15番札所','だいじゅうごばんふだしょ', 'daijyugobanfudasyo','国分寺', 'こくぶんじ', 'kokubunji', 36)
 ,(16,'第16番札所','だいじゅうろくばんふだしょ', 'daijyurokubanfudasyo','観音寺', 'かんおんじ', 'kanonji', 36)
 ,(17,'第17番札所','だいじゅうななばんふだしょ', 'daijyunanabanfudasyo','井戸寺', 'いどじ', 'idoji', 36)
 ,(18,'第18番札所','だいじゅうはちばんふだしょ', 'daijyuhachibanfudasyo','恩山寺', 'おんざんじ', 'onzanji', 36) 
 ,(19,'第19番札所','だいじゅうきゅうばんふだしょ', 'daijyukyubanfudasyo','立江寺', 'りつえじ', 'ritsuenji', 36)
 ,(20,'第20番札所','だいにじゅうばんふだしょ', 'dainijyubanfudasyo','鶴林寺', ' かくりんじ', 'kakurinji', 36)
 ,(21,'第21番札所','だいにじゅういちばんふだしょ', 'dainijyuichibanfudasyo','太龍寺', 'たいりゅうじ', 'tairyuji', 36)
 ,(22,'第22番札所','だいにじゅうにばんふだしょ', 'dainijyunibanfudasyo', '平等寺', 'びょうどうじ', 'byoudouji', 36)
 ,(23,'第23番札所','だいにじゅうさんばんふだしょ', 'dainijyusanbanfudasyo','薬王寺', 'やくおうじ', 'yakuouji', 36)
 ,(24,'第24番札所','だいにじゅうよんばんふだしょ', 'dainijyuyonbanfudasyo', '最御崎寺', 'ほつみさきじ', 'hotsumisakiji', 39)
 ,(25,'第25番札所','だいにじゅうごばんふだしょ', 'dainijyugobanfudasyo', '津照寺', 'しんしょうじ', 'shinsyouji', 39)
 ,(26,'第26番札所','だいにじゅうろくばんふだしょ', 'dainijyurokubanfudasyo','金剛頂寺', 'こんごうちょうじ', 'kongoutyouji', 39)
 ,(27,'第27番札所','だいにじゅうななばんふだしょ', 'dainijyunanabanfudasyo','神峰寺', 'こうのみねじ', 'kounomineji', 39)
 ,(28,'第28番札所','だいにじゅうはちばんふだしょ', 'dainijyuhachibanfudasyo','大日寺', 'だいにちじ', 'dainichiji', 39) 
 ,(29,'第29番札所','だいにじゅうきゅうばんふだしょ', 'dainijyukyubanfudasyo','国分寺', 'こくぶんじ', 'kokubunji', 39)
 ,(30,'第30番札所','だいさんじゅうばんふだしょ', 'daisanjyubanfudasyo','善楽寺', 'ぜんらくじ', 'zenrakuji', 39)
 ,(31,'第31番札所','だいさんじゅういちばんふだしょ', 'daisanjyuichibanfudasyo','竹林寺', 'ちくりんじ', 'chikurinji', 39)
 ,(32,'第32番札所','だいさんじゅうにばんふだしょ', 'daisanjyunibanfudasyo','禅師峰寺', 'ぜんじぶじ', 'zenjibuji', 39)
 ,(33,'第33番札所','だいさんじゅうさんばんふだしょ', 'daisanjyusanbanfudasyo','雪蹊寺', 'せっけいじ', 'sekkeiji', 39)
 ,(34,'第34番札所','だいさんじゅうよんばんふだしょ', 'daisanjyuyonbanfudasyo','種間寺', 'たねまじ', 'tamaneji', 39)
 ,(35,'第35番札所','だいさんじゅうごばんふだしょ', 'daisanjyugobanfudasyo','清滝寺', 'きよたきじ', 'kiyotakiji', 39)
 ,(36,'第36番札所','だいさんじゅうろくばんふだしょ', 'daisanjyurokubanfudasyo','青龍寺', 'しょうりゅうじ', 'syouryuji', 39)
 ,(37,'第37番札所','だいさんじゅうななばんふだしょ', 'daisanjyunanabanfudasyo','岩本寺', 'いわもとじ', 'iwamotoji', 39)
 ,(38,'第38番札所','だいさんじゅうはちばんふだしょ', 'daisanjyuhachibanfudasyo','金剛福寺', 'こんごうふくじ', 'kongoufukuji', 39)
 ,(39,'第39番札所','だいさんじゅうきゅうばんふだしょ', 'daisanjyukyubanfudasyo','延光寺', 'えんこうじ', 'enkouji', 39)
 ,(40,'第40番札所','だいよんじゅうばんふだしょ', 'daiyonjyubanfudasyo','観自在寺', 'かんじざいじ', 'kanjizaiji', 38)
 ,(41,'第41番札所','だいよんじゅういちばんふだしょ', 'daiyonjyuichibanfudasyo','龍光寺', 'りゅうこうじ', 'ryukouji', 38)
 ,(42,'第42番札所','だいよんじゅうにばんふだしょ', 'daiyonjyunibanfudasyo','佛木寺', 'ぶつもくじ', 'butsumokuji', 38)
 ,(43,'第43番札所','だいよんじゅうさんばんふだしょ', 'daiyonjyusanbanfudasyo','明石寺', 'あげいしじ', 'ageishiji', 38)
 ,(44,'第44番札所','だいよんじゅうよんばんふだしょ', 'daiyonjyuyonbanfudasyo','大宝寺', 'だいほうじ', 'daihouji', 38)
 ,(45,'第45番札所','だいよんじゅうごばんふだしょ', 'daiyonjyugobanfudasyo','岩屋寺', 'いわやじ', 'iwayaji', 38)
 ,(46,'第46番札所','だいよんじゅうろくばんふだしょ', 'daiyonjyurokubanfudasyo','浄瑠璃寺', 'じょうるりじ', 'jyoururiji', 38)
 ,(47,'第47番札所','だいよんじゅうななばんふだしょ', 'daiyonjyunanabanfudasyo','八坂寺', 'やさかじ', 'yasakaji', 38)
 ,(48,'第48番札所','だいよんじゅうはちばんふだしょ', 'daiyonjyuhachibanfudasyo','西林寺', 'さいりんじ', 'sairinji', 38)
 ,(49,'第49番札所','だいよんじゅうきゅうばんふだしょ', 'daiyonjyukyubanfudasyo','浄土寺', 'じょうどじ', 'jyoudoji', 38)
 ,(50,'第50番札所','だいごじゅうばんふだしょ', 'daigojyubanbanfudasyo','繁多寺', 'はんたじ', 'hantaji', 38)
 ,(51,'第51番札所','だいごじゅういちばんふだしょ', 'daigojyuichibanfudasyo','石手寺', 'いしてじ', 'ishiteji', 38)
 ,(52,'第52番札所','だいごじゅうにばんふだしょ', 'daigojyunibanfudasyo','太山寺', 'たいさんじ', 'taisaiji', 38)
 ,(53,'第53番札所','だいごじゅうさんばんふだしょ', 'daigojyusanbanfudasyo','円明寺', 'えんみょうじ', 'enmyouji', 38) 
 ,(54,'第54番札所','だいごじゅうよんばんふだしょ', 'daigojyuyonbanfudasyo','延命寺', 'えんめいじ', 'enmeiji', 38)
 ,(55,'第55番札所','だいごじゅうごばんふだしょ', 'daigojyugobanfudasyo','南光坊', 'なんこうぼう', 'nankoubou', 38)
 ,(56,'第56番札所','だいごじゅうろくばんふだしょ', 'daigojyurokubanfudasyo','泰山寺', 'たいさんじ', 'taisanji', 38)
 ,(57,'第57番札所','だいごじゅうななばんふだしょ', 'daigojyunanabanfudasyo','栄福寺', 'えいふくじ', 'eifukuji', 38)
 ,(58,'第58番札所','だいごじゅうはちばんふだしょ', 'daigojyuhachiichibanfudasyo','仙遊寺', 'せんゆうじ', 'senyuuji', 38)
 ,(59,'第59番札所','だいごじゅうきゅうばんふだしょ', 'daigojyukyubanfudasyo','国分寺', 'こくぶんじ', 'kokubunji', 38)
 ,(60,'第60番札所','だいろくじゅうばんふだしょ', 'dairokujyubanfudasyo','横峰寺', 'よこみねじ', 'yokomineji', 38)
 ,(61,'第61番札所','だいろくじゅういちばんふだしょ', 'dairokujyuichibanfudasyo','香園寺', 'こうおんじ', 'kouonji', 38)
 ,(62,'第62番札所','だいろくじゅうにばんふだしょ', 'dairokujyunibanfudasyo','宝寿寺', 'ほうじゅじ', 'houjyuji', 38)
 ,(63,'第63番札所','だいろくじゅうさんばんふだしょ', 'dairokujyusanbanfudasyo','吉祥寺', 'きっしょうじ', 'kissyouji', 38)
 ,(64,'第64番札所','だいろくじゅうよんばんふだしょ', 'dairokujyuyonbanfudasyo','前神寺', 'まえがみじ', 'maegamiji', 38)
 ,(65,'第65番札所','だいろくじゅうごばんふだしょ', 'dairokujyugobanfudasyo','三角寺', 'さんかくじ', 'sankakuji', 38)
 ,(66,'第66番札所','だいろくじゅうろくばんふだしょ', 'dairokujyurokubanfudasyo','雲辺寺', 'うんべんじ', 'unbenji', 37)
 ,(67,'第67番札所','だいろくじゅうななばんふだしょ', 'dairokujyunanabanfudasyo','大興寺', 'だいこうじ', 'daikouji', 37)
 ,(68,'第68番札所','だいろくじゅうはちばんふだしょ', 'dairokujyuhachibanfudasyo','神恵院', 'じんねいん', 'jinnein', 37)
 ,(69,'第69番札所','だいろくじゅうきゅうばんふだしょ', 'dairokujyukyubanfudasyo','観音寺', 'かんおんじ', 'kanonji', 37)
 ,(70,'第70番札所','だいななじゅうばんふだしょ', 'dainanajyubanfudasyo','本山寺', 'もとやまじ', 'motoyamaji', 37)
 ,(71,'第71番札所','だいななじゅういちばんふだしょ', 'dainanajyuichibanfudasyo','弥谷寺', 'いやだにじ', 'iyadaniji', 37)
 ,(72,'第72番札所','だいななじゅうにばんふだしょ', 'dainanajyunibanfudasyo','曼茶羅寺', 'まんだらじ', 'mandaraji', 37)
 ,(73,'第73番札所','だいななじゅうさんばんふだしょ', 'dainanajyusanbanfudasyo','出釈迦寺', 'しゅっしゃかじ', 'syussyakaji', 37)
 ,(74,'第74番札所','だいななじゅうよんばんふだしょ', 'dainanajyuyonbanfudasyo','甲山寺', 'こうやまじ', 'kouyamaji', 37)
 ,(75,'第75番札所','だいななじゅうごばんふだしょ', 'dainanajyugobanfudasyo','善通寺', 'ぜんつうじ', 'zentsuuji', 37)
 ,(76,'第76番札所','だいななじゅうろくばんふだしょ', 'dainanajyurokubanfudasyo','金倉寺', 'こうぞうじ', 'kouzouji', 37)
 ,(77,'第77番札所','だいななじゅうななばんふだしょ', 'dainanajyunanabanfudasyo','道隆寺', 'どうりゅうじ', 'douryuuji', 37)
 ,(78,'第78番札所','だいななじゅうはちばんふだしょ', 'dainanajyuhachibanfudasyo','郷照寺', 'ごうしょうじ', 'gousyouji', 37)
 ,(79,'第79番札所','だいななじゅうきゅうばんふだしょ', 'dainanajyukyubanfudasyo','高照院', 'こうしょういん', 'kousyouin', 37)
 ,(80,'第80番札所','だいはちじゅうばんふだしょ', 'daihachijyubanfudasyo','国分寺', 'こくぶんじ', 'kokubunji', 37)
 ,(81,'第81番札所','だいはちじゅういちばんふだしょ', 'daihachijyuichibanfudasyo','白峯寺', 'しろみねじ', 'shiromineji', 37)
 ,(82,'第82番札所','だいはちじゅうにばんふだしょ', 'daihachijyunibanfudasyo','根香寺', 'ねごろじ', 'negoroji', 37)
 ,(83,'第83番札所','だいはちじゅうさんばんふだしょ', 'daihachijyusanbanfudasyo','一宮寺', 'いちのみやじ', 'ichinomiya', 37)
 ,(84,'第84番札所','だいはちじゅうよんばんふだしょ', 'daihachijyuyonbanfudasyo','屋島寺', 'やしまじ', 'yashimaji', 37)
 ,(85,'第85番札所','だいはちじゅうごばんふだしょ', 'daihachijyugobanfudasyo','八栗寺', 'やくりじ', 'yakuriji', 37)
 ,(86,'第86番札所','だいはちじゅうろくばんふだしょ', 'daihachijyurokubanfudasyo','志度寺', 'しどじ', 'shidoji', 37)
 ,(87,'第87番札所','だいはちじゅうななばんふだしょ', 'daihachijyunanabanfudasyo','長尾寺', 'ながおじ', 'nagaoji', 37)
 ,(88,'第88番札所','だいはちじゅうはちばんふだしょ', 'daihachijyuhachibanfudasyo','大窪寺', 'おおくぼじ', 'ookuboji', 37);

Spring Bootで試してます。

■/jpa-example/build.gradle

plugins {
	id 'org.springframework.boot' version '2.7.4'
	id 'io.spring.dependency-management' version '1.0.14.RELEASE'
	id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	runtimeOnly 'org.postgresql:postgresql'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
	useJUnitPlatform()
}

■/jpa-example/src/main/resources/application.properties

spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5434/test
spring.datasource.username=postgres
spring.datasource.password=postgres    

■/jpa-example/src/main/java/com/example/demo/entity/ShikokuOhenro.java

package com.example.demo.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.Builder;
import lombok.Data;

@Entity
@Table(name="shikoku_ohenro")
@Data
@Builder
public class ShikokuOhenro {

  @Id
  @GeneratedValue(strategy=GenerationType.IDENTITY)
  private Long id;
  
  @Column(name="name_fudasyo")
  private String nameFudasyo;
  
  @Column(name="kana_name_fudasyo")
  private String kanaNameFudasyo;
  
  @Column(name="rome_name_fudasyo")
  private String romeNameFudasyo;
  
  @Column(name="name_temple")
  private String nameTemple;
  
  @Column(name="kana_name_temple")
  private String kanaNameTemple;
  
  @Column(name="rome_name_temple")
  private String romeNameTemple;
  
  @Column(name="prefectures_id")
  private Long prefecturesId;
  
}

■/jpa-example/src/main/java/com/example/demo/entity/Prefectures.java

package com.example.demo.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.Builder;
import lombok.Data;

@Entity
@Table(name="prefectures")
@Data
@Builder
public class Prefectures {

	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private Long id;
	
	@Column(name="name_prefecture")
	private String namePrefecture;
	
	@Column(name="kana_name_prefecture")
	private String kanaNamePrefecture;
	
	@Column(name="rome_name_prefecture")
	private String romeNamePrefecture;
	
	@Column(name="name_prefectural_capital")
	private String namePrefecturalCapital;
	
	@Column(name="kana_name_prefectural_capital")
	private String kanaNamePrefecturalCapital;
	
	@Column(name="rome_name_prefectural_capital")
	private String romeNamePrefecturalCapital;
	
	@Column(name="area_id")
	private Long areaId;
	
}

■/jpa-example/src/main/java/com/example/demo/entity/custom/ShikokuOhenroInfo.java

package com.example.demo.entity.custom;

import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class ShikokuOhenroInfo {

	private String nameFudasyo;
	
	private String kanaNameFudasyo;
	
	private String romeNameFudasyo;
	
	private String nameTemplate;
	
	private String kanaNameTemplate;
	
	private String romeNameTemplate;
	
	private String namePrefecture;
	
	private String kanaNamePrefecture;
	
	private String romeNamePrefecture;
	
	private String namePrefecturalCapital;
	
	private String kanaNamePrefecturalCapital;
	
	private String romeNamePrefecturalCapital;
}

■/jpa-example/src/main/java/com/example/demo/repository/ShikokuOhenroRepository.java

package com.example.demo.repository;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import com.example.demo.entity.ShikokuOhenro;

public interface ShikokuOhenroRepository extends JpaRepository<ShikokuOhenro, Long> {

	@Query(value="SELECT "
			+ "so.name_fudasyo "
			+ ", so.kana_name_fudasyo "
			+ ", so.rome_name_fudasyo "
			+ ", so.name_temple "
			+ ", so.kana_name_temple "
			+ ", so.rome_name_temple "
			+ ", p.name_prefecture "
			+ ", p.kana_name_prefecture "
			+ ", p.rome_name_prefecture "
			+ ", p.name_prefectural_capital "
			+ ", p.kana_name_prefectural_capital "
			+ ", p.rome_name_prefectural_capital "
			+ "FROM shikoku_ohenro so "
			+ "LEFT JOIN prefectures p ON so.prefectures_id = p.id "
			, nativeQuery=true)
	List<Object[]> findOhenroInfo();
}

■/jpa-example/src/main/java/com/example/demo/service/ShikokuOhenroServiceImpl.java

package com.example.demo.service;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.example.demo.entity.custom.ShikokuOhenroInfo;
import com.example.demo.repository.ShikokuOhenroRepository;

@Service
public class ShikokuOhenroServiceImpl {

	@Autowired
	private ShikokuOhenroRepository shikokuOhenroRepository;
	
	public List<ShikokuOhenroInfo> findShikokuOhenroInfo () {
		List<Object[]> shikokuOhenroInfoObjList = shikokuOhenroRepository.findOhenroInfo();
		
		List<ShikokuOhenroInfo> shikokuOhenroInfoList = new ArrayList<>();
		for (Object[] objArr: shikokuOhenroInfoObjList) {
			shikokuOhenroInfoList.add(ShikokuOhenroInfo.builder()
			  .nameFudasyo(Objects.nonNull(objArr[0])? objArr[0].toString(): null)
			  .kanaNameFudasyo(Objects.nonNull(objArr[1])? objArr[1].toString(): null)
			  .romeNameFudasyo(Objects.nonNull(objArr[2])? objArr[2].toString(): null)
			  .nameTemplate(Objects.nonNull(objArr[3])? objArr[3].toString(): null)
			  .kanaNameTemplate(Objects.nonNull(objArr[4])? objArr[4].toString(): null)
			  .romeNameTemplate(Objects.nonNull(objArr[5])? objArr[5].toString(): null)
			  .namePrefecture(Objects.nonNull(objArr[6])? objArr[6].toString(): null)
			  .kanaNamePrefecture(Objects.nonNull(objArr[7])? objArr[7].toString(): null)
			  .romeNamePrefecture(Objects.nonNull(objArr[8])? objArr[8].toString(): null)
			  .namePrefecturalCapital(Objects.nonNull(objArr[9])? objArr[9].toString(): null)
			  .kanaNamePrefecturalCapital(Objects.nonNull(objArr[10])? objArr[10].toString(): null)
			  .romeNamePrefecturalCapital(Objects.nonNull(objArr[11])? objArr[11].toString(): null)
			  .build());
		}
		return shikokuOhenroInfoList;
	}
}
   

■/jpa-example/src/main/java/com/example/demo/controller/ShikokuOhenroController.java

package com.example.demo.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import com.example.demo.entity.custom.ShikokuOhenroInfo;
import com.example.demo.service.ShikokuOhenroServiceImpl;

@RestController
public class ShikokuOhenroController {

	@Autowired
	private ShikokuOhenroServiceImpl shikokuOhenroServiceImpl;
	
	@GetMapping(value="shikoku-ohenro-info")
	public List<ShikokuOhenroInfo> findShikokuOhenroInfo() {
		return shikokuOhenroServiceImpl.findShikokuOhenroInfo();
	}
}

⇧ で、実行して、ブラウザでアクセスすると、

⇧ 取得はできてる模様。

う~む、JPAJava Persistence API)でnativeQueryを実施する場合、どうするのがベストプラクティスなんだろうか...

毎度モヤモヤ感が半端ない...

今回はこのへんで。