teratail header banner
teratail header banner
質問するログイン新規登録

質問編集履歴

2

単体のエンティティからの検索はできましたが、コンストラクタを通すと失敗します。

2019/12/27 11:50

投稿

yuki_mita
yuki_mita

スコア5

title CHANGED
File without changes
body CHANGED
@@ -1,9 +1,11 @@
1
1
  ### 前提・実現したいこと
2
2
 
3
3
  プログラミングを始めて三か月半の初心者です。
4
- JPQLで複数のデータベースを結合して検索し、結果をビューに一覧表示したいところで詰まっています。
5
- 下記の三つのテーブルを使用します。{}がテーブル名、以下","で区切られているのがカラム名です。
6
4
 
5
+ Hibernateを使って複数のエンティティからデータを検索する方法を知りたいです。
6
+
7
+ 前提として、下記の三つのテーブルを使用します。{}がテーブル名、以下","で区切られているのがカラム名です。
8
+
7
9
  - {Highlight}
8
10
  id, video_id, highlight, comment, user_id, created_at, updated_at, public_flag
9
11
  - {Video}
@@ -14,7 +16,7 @@
14
16
  Highlightテーブルのvideo_idをVideoテーブルにあるidに、user_idをUserテーブルにあるidにそれぞれ結合させます。
15
17
  VideoとHighlight、UserとHighlightがそれぞれ一対多の関係性です。
16
18
 
17
- Hibernateを利用して、複数のデータを検索するJPQL文を書きました。その一例です。
19
+ 下記はJPQL文の一例です。
18
20
  ```
19
21
  SELECT h.id, h.highlight, h.updated_at, h.public_flag, v.title, u.name, u.delete_flag FROM Highlight h JOIN Video v ON video_id = v.id JOIN User u ON user_id = u.id ORDER BY h.id DESC
20
22
  ```
@@ -38,62 +40,34 @@
38
40
  ### 該当のソースコード
39
41
  一覧の並び順を変えるため、JPQL文の内容を分岐させるクラスを作成しています。
40
42
  ```
41
- package action.highlights;
43
+ package action.videos;
42
44
 
43
- public class SearchHighlight {
45
+ public class SearchVideo {
44
46
  public static String IndexSortMethod(Integer n) {
45
- String[] isList = new String[6];
47
+ String[] isList = new String[4];
46
48
 
47
- isList[0] = "h.id DESC";
49
+ isList[0] = "v.id DESC";
48
- isList[1] = "h.id ASC";
50
+ isList[1] = "v.id ASC";
49
- isList[2] = "h.highlight DESC";
51
+ isList[2] = "v.title DESC";
50
- isList[3] = "h.highlight ASC";
52
+ isList[3] = "v.title ASC";
51
- isList[4] = "h.access DESC";
52
- isList[5] = "h.access ASC";
53
53
 
54
- StringBuilder is = new StringBuilder("SELECT h.id, h.highlight, h.updated_at, h.public_flag, v.title, u.name, u.delete_flag FROM Highlight h JOIN Video v ON video_id = v.id JOIN User u ON user_id = u.id ORDER BY ");
54
+ StringBuilder is = new StringBuilder("SELECT v.id, v.youtube_id, v.title, v.publishedAt, v.thumbnail FROM Video v ORDER BY ");
55
55
  is.append(isList[n]);
56
56
  String indexSort = is.toString();
57
57
 
58
+ // String indexSort = "SELECT v FROM Video AS v ORDER BY v.id DESC";
59
+
58
60
  return indexSort;
59
61
  }
60
62
  }
63
+
61
64
  ```
62
65
  一覧表示させるためのサーブレット
63
66
  ```
64
- package controllers.highlights;
65
67
 
66
- import java.io.IOException;
67
- import java.util.List;
68
+ // ...
68
69
 
69
- import javax.persistence.EntityManager;
70
- import javax.servlet.RequestDispatcher;
71
- import javax.servlet.ServletException;
72
- import javax.servlet.annotation.WebServlet;
73
- import javax.servlet.http.HttpServlet;
74
- import javax.servlet.http.HttpServletRequest;
75
- import javax.servlet.http.HttpServletResponse;
76
-
77
- import action.highlights.SearchHighlight;
78
- import models.highlights.IndexHighlight;
79
- import utils.DBUtil;
80
-
81
- /**
82
- * Servlet implementation class HighlightsIndexServlet
83
- */
84
- @WebServlet("/highlights/index")
85
- public class HighlightsIndexServlet extends HttpServlet {
86
- private static final long serialVersionUID = 1L;
87
-
88
70
  /**
89
- * @see HttpServlet#HttpServlet()
90
- */
91
- public HighlightsIndexServlet() {
92
- super();
93
- // TODO Auto-generated constructor stub
94
- }
95
-
96
- /**
97
71
  * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
98
72
  */
99
73
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
@@ -118,86 +92,124 @@
118
92
  if(request.getParameter("indexSort") != null && !request.getParameter("indexSort").equals("")) {
119
93
  sortNumber = Integer.parseInt(request.getParameter("indexSort"));
120
94
  }
121
- String sort = SearchHighlight.IndexSortMethod(sortNumber);
95
+ String sort = SearchVideo.IndexSortMethod(sortNumber);
122
- List<IndexHighlight> highlights = em.createQuery(sort, IndexHighlight.class)
96
+ List<Video> videos = em.createQuery(sort, Video.class)
123
97
  .setFirstResult(lines_per_page * (page - 1))
124
98
  .setMaxResults(lines_per_page)
125
99
  .getResultList();
126
100
 
101
+ long videos_count = (long)em.createNamedQuery("getVideosCount", Long.class)
102
+ .getSingleResult();
103
+
104
+ em.close();
105
+
127
106
  // ...
107
+
128
108
  }
129
109
  ```
130
- 検索したデータをそれぞれの変数に格納するコンストラクタ
110
+ 検索したデータをそれぞれの変数に格納するコンストラクタ(Video)
131
111
  ```
132
- package models.highlights;
133
112
 
113
+ // ...
114
+
115
+ package models.videos;
116
+
117
+ import java.sql.Blob;
134
118
  import java.sql.Timestamp;
135
119
 
136
- public class IndexHighlight {
120
+ public class IndexVideo {
137
121
  private Integer id;
138
- private String highlight;
122
+ private String youtube_id;
139
- private Timestamp updated_at;
140
- private Integer public_flag;
141
123
  private String title;
124
+ private Timestamp publishedAt;
142
- private String name;
125
+ private Blob thumbnail;
143
- private Integer delete_flag;
144
126
 
145
- public IndexHighlight() {}
127
+ public IndexVideo() {}
146
128
 
147
- public IndexHighlight(Integer id, String highlight, Timestamp updated_at, Integer public_flag, String title, String name, Integer delete_flag) {
129
+ public IndexVideo(Integer id, String youtube_id, String title, Timestamp publishedAt, Blob thumbnail) {
148
130
  this.id = id;
149
- this.highlight = highlight;
150
- this.updated_at = updated_at;
131
+ this.youtube_id = youtube_id;
151
- this.public_flag = public_flag;
152
132
  this.title = title;
133
+ this.publishedAt = publishedAt;
153
- this.name = name;
134
+ this.thumbnail = thumbnail;
154
- this.delete_flag = delete_flag;
155
135
  }
156
136
 
157
137
  // 以下、getter/setter
138
+
158
139
  ```
159
140
  結果を一覧表示させるビュー
160
141
  ```
161
- <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
142
+
162
- <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
143
+ // ...
163
- <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
144
+
164
145
  <c:import url="../layout/app.jsp">
165
146
  <c:param name="content">
166
- <c:if test="${flush != null}">
167
- <div id="${flush_success}">
168
- <c:out value="${flush}"></c:out>
147
+ <h2><a href="<c:url value='/videos/index' />">けそポテトチャンネルの動画</a></h2>
169
- </div>
170
- </c:if>
171
148
 
172
- <h2><a href="<c:url value='/highlights/index' />">名シーン一覧</a></h2>
173
-
174
- <form method="GET" action="<c:url value='/highlights/index' />">
149
+ <form method="GET" action="<c:url value='/videos/index' />">
175
150
  <select name="indexSort">
176
151
  <option value="">並び替え</option>
177
152
  <option value="0">投稿日△</option>
178
153
  <option value="1">投稿日▽</option>
179
154
  <option value="2">タイトル△</option>
180
155
  <option value="3">タイトル▽</option>
181
- <option value="4">アクセス数△</option>
182
- <option value="5">アクセス数▽</option>
183
156
  </select>
184
157
  <button type="submit">決定</button>
185
158
  </form>
186
159
 
187
160
  // ...
161
+
188
162
  ```
189
- HighlightテーブルのDTO
163
+ VideoテーブルのDTO
190
164
  ```
165
+
191
- @Table(name = "highlights")
166
+ // ...
167
+
192
168
  @Entity
169
+ public class Video {
170
+ @Id
171
+ @Column(name = "id")
172
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
173
+ private Integer id;
174
+
175
+ @Column(name = "youtube_id", nullable = false, unique = true)
176
+ private String youtube_id;
177
+
178
+ @Column(name = "title", nullable = false)
179
+ private String title;
180
+
181
+ @Column(name = "publishedAt", nullable = false)
182
+ private Timestamp publishedAt;
183
+
184
+ @Column(name = "thumbnail", nullable = false)
185
+ private Blob thumbnail;
186
+
187
+ @Column(name = "tag")
188
+ private String tag;
189
+
190
+ @Column(name = "taisyo", nullable = false)
191
+ private Integer taisyo;
192
+
193
+ @OneToMany(mappedBy = "video")
194
+ private List<Highlight> highlights;
195
+
196
+ // 以下、getter/setter
197
+
198
+ ```
199
+ HighlightテーブルのDTOクラス
200
+ ```
201
+
202
+ // ...
203
+
204
+ @Entity
193
205
  public class Highlight {
194
206
  @Id
195
207
  @Column(name = "id")
196
208
  @GeneratedValue(strategy = GenerationType.IDENTITY)
197
209
  private Integer id;
198
210
 
199
- @Column(name = "video_id", nullable = false)
211
+ // @Column(name = "video_id", nullable = false)
200
- private Integer video_id;
212
+ // private Integer video_id;
201
213
 
202
214
  @Column(name = "highlight", length = 255, nullable = false, unique = true)
203
215
  private String highlight;
@@ -208,8 +220,8 @@
208
220
  @Column(name = "highlight_time")
209
221
  private Time highlight_time;
210
222
 
211
- @Column(name = "user_id")
223
+ // @Column(name = "user_id")
212
- private Integer user_id;
224
+ // private Integer user_id;
213
225
 
214
226
  @Column(name = "created_at", nullable = false)
215
227
  private Timestamp created_at;
@@ -228,9 +240,11 @@
228
240
 
229
241
  // 以下、getter/setter
230
242
  ```
231
- UserテーブルのDTO
243
+ UserテーブルのDTOクラス
232
244
  ```
245
+
233
- @Table(name = "users")
246
+ // ...
247
+
234
248
  @Entity
235
249
  public class User {
236
250
  @Id
@@ -257,47 +271,33 @@
257
271
  private List<Highlight> highlights;
258
272
 
259
273
  // 以下、getter/setter
274
+
260
275
  ```
261
- VideoテーブルのDTO
262
- ```
263
- @Table(name = "videos")
264
- @Entity
265
- public class Video {
266
- @Id
267
- @Column(name = "id")
268
- @GeneratedValue(strategy = GenerationType.IDENTITY)
269
- private Integer id;
270
276
 
271
- @Column(name = "youtube_id", nullable = false, unique = true)
272
- private String youtube_id;
277
+ ### 試したこと
273
278
 
274
- @Column(name = "title", nullable = false)
279
+ それぞれのテーブルのDTOにOneToMany、ManyToOneのアノテーションを記述しました。
275
- private String title;
276
280
 
277
- @Column(name = "publishedAt", nullable = false)
278
- private Timestamp publishedAt;
281
+ ### 追記
279
282
 
280
- @Column(name = "thumbnail", nullable = false)
283
+ 別クラスに作成したコンストラクタを介さずに、単体のエンティティからデータを検索することはできました。しかし、コンストラクタを通すと単体のエンティティを検索してもエラーが表示されてしまいます。複数のエンティティの場合でも同様です。
281
- private Blob thumbnail;
284
+ つまり、コンストラクタが上手く機能していないようなのです。
285
+ ```
286
+ HTTP ERROR 500
282
287
 
283
- @Column(name = "tag")
288
+ Problem accessing /videos/index. Reason:
284
- private String tag;
289
+ Server Error
285
290
 
286
- @Column(name = "taisyo", nullable = false)
287
- private Integer taisyo;
288
291
 
292
+ Caused by:
289
- @OneToMany(mappedBy = "video")
293
+ java.lang.IllegalArgumentException: Cannot create TypedQuery for query with more than one return using requested result type [models.videos.IndexVideo]
290
- private List<Highlight> highlights;
291
294
 
292
- // 以下、getter/setter
295
+ // ...
296
+
293
297
  ```
294
298
 
295
- ### 試し
299
+ なお、OneToMany(VideoクラスとUserクラス)とManyToOne(Highlightクラス)のアノテーションをそれぞれDTOに記載するにあって、Videoテーブルのidに対応するvideo_idカラムUserテーブルのidに対応するuser_idを消しました(コメント状態にした部分です)。
296
300
 
297
- 別パッケージにコンストラクタを作り、MySQLから検索してくるデータにそれぞれ変数を宣言しました。
298
- ビューから送られてきたidによってJPQL分の一部を分岐させられるようにしました(並び替え表示をするためです)。
299
- それぞれのテーブルのDTOにOneToMany、ManyToOneのアノテーションを記述しました。
300
-
301
301
  ### 最後に
302
302
  質問が大変長く、コードの内容に至らない点が散見されると思いますが、ご回答のほどお待ちしております。
303
303
 

1

2019/12/27 11:50

投稿

yuki_mita
yuki_mita

スコア5

title CHANGED
File without changes
body CHANGED
@@ -12,6 +12,7 @@
12
12
  id, name, address, created_at, delete_flag
13
13
 
14
14
  Highlightテーブルのvideo_idをVideoテーブルにあるidに、user_idをUserテーブルにあるidにそれぞれ結合させます。
15
+ VideoとHighlight、UserとHighlightがそれぞれ一対多の関係性です。
15
16
 
16
17
  Hibernateを利用して、複数のデータを検索するJPQL文を書きました。その一例です。
17
18
  ```