質問編集履歴

2

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

2019/12/27 11:50

投稿

yuki_mita
yuki_mita

スコア5

test CHANGED
File without changes
test CHANGED
@@ -4,9 +4,13 @@
4
4
 
5
5
  プログラミングを始めて三か月半の初心者です。
6
6
 
7
+
8
+
7
- JPQLで複数のデータベース結合して検索し、結果ビューに一覧表示したいところ詰まっています。
9
+ Hibernateを使って複数のエンティティからデータを検索する方法知りたいです。
8
-
10
+
11
+
12
+
9
- 下記の三つのテーブルを使用します。{}がテーブル名、以下","で区切られているのがカラム名です。
13
+ 前提として、下記の三つのテーブルを使用します。{}がテーブル名、以下","で区切られているのがカラム名です。
10
14
 
11
15
 
12
16
 
@@ -30,7 +34,7 @@
30
34
 
31
35
 
32
36
 
33
- Hibernateを利用して、複数のデータを検索するJPQL文を書きました。その一例です。
37
+ 下記はJPQL文の一例です。
34
38
 
35
39
  ```
36
40
 
@@ -78,33 +82,29 @@
78
82
 
79
83
  ```
80
84
 
81
- package action.highlights;
85
+ package action.videos;
82
-
83
-
84
-
86
+
87
+
88
+
85
- public class SearchHighlight {
89
+ public class SearchVideo {
86
90
 
87
91
  public static String IndexSortMethod(Integer n) {
88
92
 
89
- String[] isList = new String[6];
90
-
91
-
92
-
93
- isList[0] = "h.id DESC";
94
-
95
- isList[1] = "h.id ASC";
96
-
97
- isList[2] = "h.highlight DESC";
98
-
99
- isList[3] = "h.highlight ASC";
100
-
101
- isList[4] = "h.access DESC";
102
-
103
- isList[5] = "h.access ASC";
104
-
105
-
106
-
107
- 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 ");
93
+ String[] isList = new String[4];
94
+
95
+
96
+
97
+ isList[0] = "v.id DESC";
98
+
99
+ isList[1] = "v.id ASC";
100
+
101
+ isList[2] = "v.title DESC";
102
+
103
+ isList[3] = "v.title ASC";
104
+
105
+
106
+
107
+ StringBuilder is = new StringBuilder("SELECT v.id, v.youtube_id, v.title, v.publishedAt, v.thumbnail FROM Video v ORDER BY ");
108
108
 
109
109
  is.append(isList[n]);
110
110
 
@@ -112,475 +112,439 @@
112
112
 
113
113
 
114
114
 
115
+ // String indexSort = "SELECT v FROM Video AS v ORDER BY v.id DESC";
116
+
117
+
118
+
115
119
  return indexSort;
116
120
 
117
121
  }
118
122
 
119
123
  }
120
124
 
125
+
126
+
121
127
  ```
122
128
 
123
129
  一覧表示させるためのサーブレット
124
130
 
125
131
  ```
126
132
 
127
- package controllers.highlights;
133
+
128
-
129
-
130
-
131
- import java.io.IOException;
134
+
132
-
133
- import java.util.List;
134
-
135
-
136
-
137
- import javax.persistence.EntityManager;
138
-
139
- import javax.servlet.RequestDispatcher;
140
-
141
- import javax.servlet.ServletException;
142
-
143
- import javax.servlet.annotation.WebServlet;
144
-
145
- import javax.servlet.http.HttpServlet;
146
-
147
- import javax.servlet.http.HttpServletRequest;
148
-
149
- import javax.servlet.http.HttpServletResponse;
150
-
151
-
152
-
153
- import action.highlights.SearchHighlight;
154
-
155
- import models.highlights.IndexHighlight;
156
-
157
- import utils.DBUtil;
158
-
159
-
160
-
161
- /**
135
+ // ...
162
-
163
- * Servlet implementation class HighlightsIndexServlet
164
-
165
- */
166
-
167
- @WebServlet("/highlights/index")
168
-
169
- public class HighlightsIndexServlet extends HttpServlet {
170
-
171
- private static final long serialVersionUID = 1L;
172
136
 
173
137
 
174
138
 
175
139
  /**
176
140
 
177
- * @see HttpServlet#HttpServlet()
141
+ * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
178
142
 
179
143
  */
180
144
 
145
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
146
+
147
+ EntityManager em = DBUtil.createEntityManager();
148
+
149
+
150
+
151
+ int page = 1;
152
+
153
+ try {
154
+
155
+ page = Integer.parseInt(request.getParameter("page"));
156
+
157
+ } catch(NumberFormatException e) { }
158
+
159
+
160
+
161
+ int lines_per_page = 10;
162
+
163
+ if (request.getSession().getAttribute("lines_per_page") != null) {
164
+
165
+ lines_per_page = (Integer)request.getSession().getAttribute("lines_per_page");
166
+
167
+ request.getSession().removeAttribute("lines_per_page");
168
+
169
+ }
170
+
171
+
172
+
173
+ try {
174
+
175
+ lines_per_page = Integer.parseInt(request.getParameter("lines_per_page"));
176
+
177
+ } catch(NumberFormatException e) { }
178
+
179
+
180
+
181
+ int sortNumber = 0;
182
+
183
+ if(request.getParameter("indexSort") != null && !request.getParameter("indexSort").equals("")) {
184
+
185
+ sortNumber = Integer.parseInt(request.getParameter("indexSort"));
186
+
187
+ }
188
+
189
+ String sort = SearchVideo.IndexSortMethod(sortNumber);
190
+
191
+ List<Video> videos = em.createQuery(sort, Video.class)
192
+
193
+ .setFirstResult(lines_per_page * (page - 1))
194
+
195
+ .setMaxResults(lines_per_page)
196
+
197
+ .getResultList();
198
+
199
+
200
+
201
+ long videos_count = (long)em.createNamedQuery("getVideosCount", Long.class)
202
+
203
+ .getSingleResult();
204
+
205
+
206
+
207
+ em.close();
208
+
209
+
210
+
211
+ // ...
212
+
213
+
214
+
215
+ }
216
+
217
+ ```
218
+
219
+ 検索したデータをそれぞれの変数に格納するコンストラクタ(Video)
220
+
221
+ ```
222
+
223
+
224
+
225
+ // ...
226
+
227
+
228
+
229
+ package models.videos;
230
+
231
+
232
+
233
+ import java.sql.Blob;
234
+
235
+ import java.sql.Timestamp;
236
+
237
+
238
+
181
- public HighlightsIndexServlet() {
239
+ public class IndexVideo {
240
+
182
-
241
+ private Integer id;
242
+
243
+ private String youtube_id;
244
+
245
+ private String title;
246
+
247
+ private Timestamp publishedAt;
248
+
249
+ private Blob thumbnail;
250
+
251
+
252
+
253
+ public IndexVideo() {}
254
+
255
+
256
+
257
+ public IndexVideo(Integer id, String youtube_id, String title, Timestamp publishedAt, Blob thumbnail) {
258
+
183
- super();
259
+ this.id = id;
184
-
260
+
185
- // TODO Auto-generated constructor stub
261
+ this.youtube_id = youtube_id;
262
+
263
+ this.title = title;
264
+
265
+ this.publishedAt = publishedAt;
266
+
267
+ this.thumbnail = thumbnail;
186
268
 
187
269
  }
188
270
 
189
271
 
190
272
 
191
- /**
192
-
193
- * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
194
-
195
- */
196
-
197
- protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
198
-
199
- EntityManager em = DBUtil.createEntityManager();
200
-
201
-
202
-
203
- int page = 1;
204
-
205
- try {
206
-
207
- page = Integer.parseInt(request.getParameter("page"));
208
-
209
- } catch(NumberFormatException e) { }
210
-
211
-
212
-
213
- int lines_per_page = 10;
214
-
215
- if (request.getSession().getAttribute("lines_per_page") != null) {
216
-
217
- lines_per_page = (Integer)request.getSession().getAttribute("lines_per_page");
218
-
219
- request.getSession().removeAttribute("lines_per_page");
220
-
221
- }
222
-
223
-
224
-
225
- try {
226
-
227
- lines_per_page = Integer.parseInt(request.getParameter("lines_per_page"));
228
-
229
- } catch(NumberFormatException e) { }
230
-
231
-
232
-
233
- int sortNumber = 0;
234
-
235
- if(request.getParameter("indexSort") != null && !request.getParameter("indexSort").equals("")) {
236
-
237
- sortNumber = Integer.parseInt(request.getParameter("indexSort"));
238
-
239
- }
240
-
241
- String sort = SearchHighlight.IndexSortMethod(sortNumber);
242
-
243
- List<IndexHighlight> highlights = em.createQuery(sort, IndexHighlight.class)
244
-
245
- .setFirstResult(lines_per_page * (page - 1))
246
-
247
- .setMaxResults(lines_per_page)
248
-
249
- .getResultList();
250
-
251
-
252
-
253
- // ...
254
-
255
- }
256
-
257
- ```
258
-
259
- 検索したデータをそれぞれの変数に格納するコンストラクタ
260
-
261
- ```
262
-
263
- package models.highlights;
264
-
265
-
266
-
267
- import java.sql.Timestamp;
268
-
269
-
270
-
271
- public class IndexHighlight {
273
+ // 以下、getter/setter
274
+
275
+
276
+
277
+ ```
278
+
279
+ 結果を一覧表示させるビュー
280
+
281
+ ```
282
+
283
+
284
+
285
+ // ...
286
+
287
+
288
+
289
+ <c:import url="../layout/app.jsp">
290
+
291
+ <c:param name="content">
292
+
293
+ <h2><a href="<c:url value='/videos/index' />">けそポテトチャンネルの動画</a></h2>
294
+
295
+
296
+
297
+ <form method="GET" action="<c:url value='/videos/index' />">
298
+
299
+ <select name="indexSort">
300
+
301
+ <option value="">並び替え</option>
302
+
303
+ <option value="0">投稿日△</option>
304
+
305
+ <option value="1">投稿日▽</option>
306
+
307
+ <option value="2">タイトル△</option>
308
+
309
+ <option value="3">タイトル▽</option>
310
+
311
+ </select>
312
+
313
+ <button type="submit">決定</button>
314
+
315
+ </form>
316
+
317
+
318
+
319
+ // ...
320
+
321
+
322
+
323
+ ```
324
+
325
+ VideoテーブルのDTO
326
+
327
+ ```
328
+
329
+
330
+
331
+ // ...
332
+
333
+
334
+
335
+ @Entity
336
+
337
+ public class Video {
338
+
339
+ @Id
340
+
341
+ @Column(name = "id")
342
+
343
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
272
344
 
273
345
  private Integer id;
274
346
 
347
+
348
+
349
+ @Column(name = "youtube_id", nullable = false, unique = true)
350
+
351
+ private String youtube_id;
352
+
353
+
354
+
355
+ @Column(name = "title", nullable = false)
356
+
357
+ private String title;
358
+
359
+
360
+
361
+ @Column(name = "publishedAt", nullable = false)
362
+
363
+ private Timestamp publishedAt;
364
+
365
+
366
+
367
+ @Column(name = "thumbnail", nullable = false)
368
+
369
+ private Blob thumbnail;
370
+
371
+
372
+
373
+ @Column(name = "tag")
374
+
375
+ private String tag;
376
+
377
+
378
+
379
+ @Column(name = "taisyo", nullable = false)
380
+
381
+ private Integer taisyo;
382
+
383
+
384
+
385
+ @OneToMany(mappedBy = "video")
386
+
387
+ private List<Highlight> highlights;
388
+
389
+
390
+
391
+ // 以下、getter/setter
392
+
393
+
394
+
395
+ ```
396
+
397
+ HighlightテーブルのDTOクラス
398
+
399
+ ```
400
+
401
+
402
+
403
+ // ...
404
+
405
+
406
+
407
+ @Entity
408
+
409
+ public class Highlight {
410
+
411
+ @Id
412
+
413
+ @Column(name = "id")
414
+
415
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
416
+
417
+ private Integer id;
418
+
419
+
420
+
421
+ // @Column(name = "video_id", nullable = false)
422
+
423
+ // private Integer video_id;
424
+
425
+
426
+
427
+ @Column(name = "highlight", length = 255, nullable = false, unique = true)
428
+
275
429
  private String highlight;
276
430
 
431
+
432
+
433
+ @Column(name = "comment")
434
+
435
+ private String comment;
436
+
437
+
438
+
439
+ @Column(name = "highlight_time")
440
+
441
+ private Time highlight_time;
442
+
443
+
444
+
445
+ // @Column(name = "user_id")
446
+
447
+ // private Integer user_id;
448
+
449
+
450
+
451
+ @Column(name = "created_at", nullable = false)
452
+
453
+ private Timestamp created_at;
454
+
455
+
456
+
457
+ @Column(name = "updated_at", nullable = false)
458
+
277
459
  private Timestamp updated_at;
278
460
 
461
+
462
+
463
+ @Column(name = "public_flag", nullable = false)
464
+
279
465
  private Integer public_flag;
280
466
 
467
+
468
+
469
+ @ManyToOne
470
+
281
- private String title;
471
+ private Video video;
472
+
473
+
474
+
475
+ @ManyToOne
476
+
477
+ private User user;
478
+
479
+
480
+
481
+ // 以下、getter/setter
482
+
483
+ ```
484
+
485
+ UserテーブルのDTOクラス
486
+
487
+ ```
488
+
489
+
490
+
491
+ // ...
492
+
493
+
494
+
495
+ @Entity
496
+
497
+ public class User {
498
+
499
+ @Id
500
+
501
+ @Column(name = "id")
502
+
503
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
504
+
505
+ private Integer id;
506
+
507
+
508
+
509
+ @Column(name = "name", nullable = false, unique = true)
282
510
 
283
511
  private String name;
284
512
 
513
+
514
+
515
+ @Column(name = "address", nullable = false)
516
+
517
+ private String address;
518
+
519
+
520
+
521
+ @Column(name = "password", length = 64, nullable = false)
522
+
523
+ private String password;
524
+
525
+
526
+
527
+ @Column(name = "created_at", nullable = false)
528
+
529
+ private Timestamp created_at;
530
+
531
+
532
+
533
+ @Column(name = "delete_flag", nullable = false)
534
+
285
535
  private Integer delete_flag;
286
536
 
287
537
 
288
538
 
289
- public IndexHighlight() {}
539
+ @OneToMany(mappedBy = "user")
290
-
291
-
292
-
293
- public IndexHighlight(Integer id, String highlight, Timestamp updated_at, Integer public_flag, String title, String name, Integer delete_flag) {
540
+
294
-
295
- this.id = id;
296
-
297
- this.highlight = highlight;
541
+ private List<Highlight> highlights;
298
-
299
- this.updated_at = updated_at;
300
-
301
- this.public_flag = public_flag;
302
-
303
- this.title = title;
304
-
305
- this.name = name;
306
-
307
- this.delete_flag = delete_flag;
308
-
309
- }
310
542
 
311
543
 
312
544
 
313
545
  // 以下、getter/setter
314
546
 
315
- ```
547
+
316
-
317
- 結果を一覧表示させるビュー
318
-
319
- ```
320
-
321
- <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
322
-
323
- <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
324
-
325
- <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
326
-
327
- <c:import url="../layout/app.jsp">
328
-
329
- <c:param name="content">
330
-
331
- <c:if test="${flush != null}">
332
-
333
- <div id="${flush_success}">
334
-
335
- <c:out value="${flush}"></c:out>
336
-
337
- </div>
338
-
339
- </c:if>
340
-
341
-
342
-
343
- <h2><a href="<c:url value='/highlights/index' />">名シーン一覧</a></h2>
344
-
345
-
346
-
347
- <form method="GET" action="<c:url value='/highlights/index' />">
348
-
349
- <select name="indexSort">
350
-
351
- <option value="">並び替え</option>
352
-
353
- <option value="0">投稿日△</option>
354
-
355
- <option value="1">投稿日▽</option>
356
-
357
- <option value="2">タイトル△</option>
358
-
359
- <option value="3">タイトル▽</option>
360
-
361
- <option value="4">アクセス数△</option>
362
-
363
- <option value="5">アクセス数▽</option>
364
-
365
- </select>
366
-
367
- <button type="submit">決定</button>
368
-
369
- </form>
370
-
371
-
372
-
373
- // ...
374
-
375
- ```
376
-
377
- HighlightテーブルのDTO
378
-
379
- ```
380
-
381
- @Table(name = "highlights")
382
-
383
- @Entity
384
-
385
- public class Highlight {
386
-
387
- @Id
388
-
389
- @Column(name = "id")
390
-
391
- @GeneratedValue(strategy = GenerationType.IDENTITY)
392
-
393
- private Integer id;
394
-
395
-
396
-
397
- @Column(name = "video_id", nullable = false)
398
-
399
- private Integer video_id;
400
-
401
-
402
-
403
- @Column(name = "highlight", length = 255, nullable = false, unique = true)
404
-
405
- private String highlight;
406
-
407
-
408
-
409
- @Column(name = "comment")
410
-
411
- private String comment;
412
-
413
-
414
-
415
- @Column(name = "highlight_time")
416
-
417
- private Time highlight_time;
418
-
419
-
420
-
421
- @Column(name = "user_id")
422
-
423
- private Integer user_id;
424
-
425
-
426
-
427
- @Column(name = "created_at", nullable = false)
428
-
429
- private Timestamp created_at;
430
-
431
-
432
-
433
- @Column(name = "updated_at", nullable = false)
434
-
435
- private Timestamp updated_at;
436
-
437
-
438
-
439
- @Column(name = "public_flag", nullable = false)
440
-
441
- private Integer public_flag;
442
-
443
-
444
-
445
- @ManyToOne
446
-
447
- private Video video;
448
-
449
-
450
-
451
- @ManyToOne
452
-
453
- private User user;
454
-
455
-
456
-
457
- // 以下、getter/setter
458
-
459
- ```
460
-
461
- UserテーブルのDTO
462
-
463
- ```
464
-
465
- @Table(name = "users")
466
-
467
- @Entity
468
-
469
- public class User {
470
-
471
- @Id
472
-
473
- @Column(name = "id")
474
-
475
- @GeneratedValue(strategy = GenerationType.IDENTITY)
476
-
477
- private Integer id;
478
-
479
-
480
-
481
- @Column(name = "name", nullable = false, unique = true)
482
-
483
- private String name;
484
-
485
-
486
-
487
- @Column(name = "address", nullable = false)
488
-
489
- private String address;
490
-
491
-
492
-
493
- @Column(name = "password", length = 64, nullable = false)
494
-
495
- private String password;
496
-
497
-
498
-
499
- @Column(name = "created_at", nullable = false)
500
-
501
- private Timestamp created_at;
502
-
503
-
504
-
505
- @Column(name = "delete_flag", nullable = false)
506
-
507
- private Integer delete_flag;
508
-
509
-
510
-
511
- @OneToMany(mappedBy = "user")
512
-
513
- private List<Highlight> highlights;
514
-
515
-
516
-
517
- // 以下、getter/setter
518
-
519
- ```
520
-
521
- VideoテーブルのDTO
522
-
523
- ```
524
-
525
- @Table(name = "videos")
526
-
527
- @Entity
528
-
529
- public class Video {
530
-
531
- @Id
532
-
533
- @Column(name = "id")
534
-
535
- @GeneratedValue(strategy = GenerationType.IDENTITY)
536
-
537
- private Integer id;
538
-
539
-
540
-
541
- @Column(name = "youtube_id", nullable = false, unique = true)
542
-
543
- private String youtube_id;
544
-
545
-
546
-
547
- @Column(name = "title", nullable = false)
548
-
549
- private String title;
550
-
551
-
552
-
553
- @Column(name = "publishedAt", nullable = false)
554
-
555
- private Timestamp publishedAt;
556
-
557
-
558
-
559
- @Column(name = "thumbnail", nullable = false)
560
-
561
- private Blob thumbnail;
562
-
563
-
564
-
565
- @Column(name = "tag")
566
-
567
- private String tag;
568
-
569
-
570
-
571
- @Column(name = "taisyo", nullable = false)
572
-
573
- private Integer taisyo;
574
-
575
-
576
-
577
- @OneToMany(mappedBy = "video")
578
-
579
- private List<Highlight> highlights;
580
-
581
-
582
-
583
- // 以下、getter/setter
584
548
 
585
549
  ```
586
550
 
@@ -590,14 +554,50 @@
590
554
 
591
555
 
592
556
 
593
- 別パッケージにコンストラクタを作り、MySQLから検索してくるデータにそれぞれ変数を宣言しました。
594
-
595
- ビューから送られてきたidによってJPQL分の一部を分岐させられるようにしました(並び替え表示をするためです)。
596
-
597
557
  それぞれのテーブルのDTOにOneToMany、ManyToOneのアノテーションを記述しました。
598
558
 
599
559
 
600
560
 
561
+ ### 追記
562
+
563
+
564
+
565
+ 別クラスに作成したコンストラクタを介さずに、単体のエンティティからデータを検索することはできました。しかし、コンストラクタを通すと単体のエンティティを検索してもエラーが表示されてしまいます。複数のエンティティの場合でも同様です。
566
+
567
+ つまり、コンストラクタが上手く機能していないようなのです。
568
+
569
+ ```
570
+
571
+ HTTP ERROR 500
572
+
573
+
574
+
575
+ Problem accessing /videos/index. Reason:
576
+
577
+ Server Error
578
+
579
+
580
+
581
+
582
+
583
+ Caused by:
584
+
585
+ java.lang.IllegalArgumentException: Cannot create TypedQuery for query with more than one return using requested result type [models.videos.IndexVideo]
586
+
587
+
588
+
589
+ // ...
590
+
591
+
592
+
593
+ ```
594
+
595
+
596
+
597
+ なお、OneToMany(VideoクラスとUserクラス)とManyToOne(Highlightクラス)のアノテーションをそれぞれDTOに記載するにあたって、Videoテーブルのidに対応するvideo_idカラムとUserテーブルのidに対応するuser_idを消しました(コメント状態にした部分です)。
598
+
599
+
600
+
601
601
  ### 最後に
602
602
 
603
603
  質問が大変長く、コードの内容に至らない点が散見されると思いますが、ご回答のほどお待ちしております。

1

2019/12/27 11:50

投稿

yuki_mita
yuki_mita

スコア5

test CHANGED
File without changes
test CHANGED
@@ -26,6 +26,8 @@
26
26
 
27
27
  Highlightテーブルのvideo_idをVideoテーブルにあるidに、user_idをUserテーブルにあるidにそれぞれ結合させます。
28
28
 
29
+ VideoとHighlight、UserとHighlightがそれぞれ一対多の関係性です。
30
+
29
31
 
30
32
 
31
33
  Hibernateを利用して、複数のデータを検索するJPQL文を書きました。その一例です。