前提・実現したいこと
プログラミングを始めて三か月半の初心者です。
Hibernateを使って複数のエンティティからデータを検索する方法を知りたいです。
前提として、下記の三つのテーブルを使用します。{}がテーブル名、以下","で区切られているのがカラム名です。
- {Highlight}
id, video_id, highlight, comment, user_id, created_at, updated_at, public_flag
- {Video}
id, youtube_id, title, publishedAt, thumbnail, tag, taisyo
- {User}
id, name, address, created_at, delete_flag
Highlightテーブルのvideo_idをVideoテーブルにあるidに、user_idをUserテーブルにあるidにそれぞれ結合させます。
VideoとHighlight、UserとHighlightがそれぞれ一対多の関係性です。
下記はJPQL文の一例です。
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
しかし、ブラウザに以下のエラーが表示されてしまいます。
発生している問題・エラーメッセージ
HTTP ERROR 500 Problem accessing /highlights/index. Reason: Server Error Caused by: javax.persistence.PersistenceException: [PersistenceUnit: keso_hane_highlight] Unable to build Hibernate SessionFactory // 長すぎるので冒頭だけ載せています。
該当のソースコード
一覧の並び順を変えるため、JPQL文の内容を分岐させるクラスを作成しています。
package action.videos; public class SearchVideo { public static String IndexSortMethod(Integer n) { String[] isList = new String[4]; isList[0] = "v.id DESC"; isList[1] = "v.id ASC"; isList[2] = "v.title DESC"; isList[3] = "v.title ASC"; StringBuilder is = new StringBuilder("SELECT v.id, v.youtube_id, v.title, v.publishedAt, v.thumbnail FROM Video v ORDER BY "); is.append(isList[n]); String indexSort = is.toString(); // String indexSort = "SELECT v FROM Video AS v ORDER BY v.id DESC"; return indexSort; } }
一覧表示させるためのサーブレット
// ... /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { EntityManager em = DBUtil.createEntityManager(); int page = 1; try { page = Integer.parseInt(request.getParameter("page")); } catch(NumberFormatException e) { } int lines_per_page = 10; if (request.getSession().getAttribute("lines_per_page") != null) { lines_per_page = (Integer)request.getSession().getAttribute("lines_per_page"); request.getSession().removeAttribute("lines_per_page"); } try { lines_per_page = Integer.parseInt(request.getParameter("lines_per_page")); } catch(NumberFormatException e) { } int sortNumber = 0; if(request.getParameter("indexSort") != null && !request.getParameter("indexSort").equals("")) { sortNumber = Integer.parseInt(request.getParameter("indexSort")); } String sort = SearchVideo.IndexSortMethod(sortNumber); List<Video> videos = em.createQuery(sort, Video.class) .setFirstResult(lines_per_page * (page - 1)) .setMaxResults(lines_per_page) .getResultList(); long videos_count = (long)em.createNamedQuery("getVideosCount", Long.class) .getSingleResult(); em.close(); // ... }
検索したデータをそれぞれの変数に格納するコンストラクタ(Video)
// ... package models.videos; import java.sql.Blob; import java.sql.Timestamp; public class IndexVideo { private Integer id; private String youtube_id; private String title; private Timestamp publishedAt; private Blob thumbnail; public IndexVideo() {} public IndexVideo(Integer id, String youtube_id, String title, Timestamp publishedAt, Blob thumbnail) { this.id = id; this.youtube_id = youtube_id; this.title = title; this.publishedAt = publishedAt; this.thumbnail = thumbnail; } // 以下、getter/setter
結果を一覧表示させるビュー
// ... <c:import url="../layout/app.jsp"> <c:param name="content"> <h2><a href="<c:url value='/videos/index' />">けそポテトチャンネルの動画</a></h2> <form method="GET" action="<c:url value='/videos/index' />"> <select name="indexSort"> <option value="">並び替え</option> <option value="0">投稿日△</option> <option value="1">投稿日▽</option> <option value="2">タイトル△</option> <option value="3">タイトル▽</option> </select> <button type="submit">決定</button> </form> // ...
VideoテーブルのDTO
// ... @Entity public class Video { @Id @Column(name = "id") @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @Column(name = "youtube_id", nullable = false, unique = true) private String youtube_id; @Column(name = "title", nullable = false) private String title; @Column(name = "publishedAt", nullable = false) private Timestamp publishedAt; @Column(name = "thumbnail", nullable = false) private Blob thumbnail; @Column(name = "tag") private String tag; @Column(name = "taisyo", nullable = false) private Integer taisyo; @OneToMany(mappedBy = "video") private List<Highlight> highlights; // 以下、getter/setter
HighlightテーブルのDTOクラス
// ... @Entity public class Highlight { @Id @Column(name = "id") @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; // @Column(name = "video_id", nullable = false) // private Integer video_id; @Column(name = "highlight", length = 255, nullable = false, unique = true) private String highlight; @Column(name = "comment") private String comment; @Column(name = "highlight_time") private Time highlight_time; // @Column(name = "user_id") // private Integer user_id; @Column(name = "created_at", nullable = false) private Timestamp created_at; @Column(name = "updated_at", nullable = false) private Timestamp updated_at; @Column(name = "public_flag", nullable = false) private Integer public_flag; @ManyToOne private Video video; @ManyToOne private User user; // 以下、getter/setter
UserテーブルのDTOクラス
// ... @Entity public class User { @Id @Column(name = "id") @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @Column(name = "name", nullable = false, unique = true) private String name; @Column(name = "address", nullable = false) private String address; @Column(name = "password", length = 64, nullable = false) private String password; @Column(name = "created_at", nullable = false) private Timestamp created_at; @Column(name = "delete_flag", nullable = false) private Integer delete_flag; @OneToMany(mappedBy = "user") private List<Highlight> highlights; // 以下、getter/setter
試したこと
それぞれのテーブルのDTOにOneToMany、ManyToOneのアノテーションを記述しました。
追記
別クラスに作成したコンストラクタを介さずに、単体のエンティティからデータを検索することはできました。しかし、コンストラクタを通すと単体のエンティティを検索してもエラーが表示されてしまいます。複数のエンティティの場合でも同様です。
つまり、コンストラクタが上手く機能していないようなのです。
HTTP ERROR 500 Problem accessing /videos/index. Reason: Server Error Caused by: java.lang.IllegalArgumentException: Cannot create TypedQuery for query with more than one return using requested result type [models.videos.IndexVideo] // ...
なお、OneToMany(VideoクラスとUserクラス)とManyToOne(Highlightクラス)のアノテーションをそれぞれDTOに記載するにあたって、Videoテーブルのidに対応するvideo_idカラムとUserテーブルのidに対応するuser_idを消しました(コメント状態にした部分です)。
最後に
質問が大変長く、コードの内容に至らない点が散見されると思いますが、ご回答のほどお待ちしております。
補足情報
IDE:eclipse
言語:Java
データベース:MySQL
回答1件
あなたの回答
tips
プレビュー