質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Java Persistence API

Java Persistance Acchitecture API (JPA) はJavaオブジェクト・クラスとリレーショナルデータベースとの間のデータへのアクセス、管理、維持を行う為のJava用のフレームワークです。

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

Spring Boot

Spring Bootは、Javaのフレームワークの一つ。Springプロジェクトが提供する様々なフレームワークを統合した、アプリケーションを高速で開発するために設計されたフレームワークです。

Q&A

解決済

2回答

8626閲覧

Spring Boot, JPAを使用したリレーション関係にあるテーブルへの一括INSERT

yamashita_yuich

総合スコア316

Java Persistence API

Java Persistance Acchitecture API (JPA) はJavaオブジェクト・クラスとリレーショナルデータベースとの間のデータへのアクセス、管理、維持を行う為のJava用のフレームワークです。

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

Spring Boot

Spring Bootは、Javaのフレームワークの一つ。Springプロジェクトが提供する様々なフレームワークを統合した、アプリケーションを高速で開発するために設計されたフレームワークです。

0グッド

1クリップ

投稿2018/07/13 10:54

編集2018/07/13 11:50
  1. 質問概要

Spring Boot を使用して、リレーション関係にあるテーブルに対して、親子同時にInsert処理を実施したいのですができません。
1テーブルずつINSERTして最後にCommitするしかないのでしょうか?

PostgreSQLのテーブルにマッピングしたPOJOクラスをRepositoryを使用してコミットしたいのですが、
その方法をご教示ください。

  1. 該当のソースコード

・リレーションの親に相当するPOJOクラス

Java

1package ***; 2 3import java.util.List; 4 5import javax.persistence.Column; 6import javax.persistence.Entity; 7import javax.persistence.Id; 8import javax.persistence.JoinColumn; 9import javax.persistence.OneToMany; 10import javax.persistence.Table; 11 12@Entity 13@Table(name = "users") 14public class User { 15 16 @Id 17 @Column(name = "uid") 18 private String uId; 19 20 @Column(name = "photo_url") 21 private String photoUrl; 22 23 @OneToMany 24 @JoinColumn(name = "uid", nullable = true) 25 private List<UserLicense> licenses; 26 27 // Getter / Setter は記載を省略

・リレーションの子に相当するPOJOクラス

Java

1package ***; 2 3import javax.persistence.Column; 4import javax.persistence.Entity; 5import javax.persistence.Id; 6import javax.persistence.Table; 7 8@Entity 9@Table(name = "user_licenses") 10public class UserLicnse { 11 12 @Id 13 @Column(name = "license_id") 14 private int licenseId; 15 16 @Column(name = "uid") 17 private String uId; 18 19 @Column(name = "authenticated") 20 private boolean authenticated; 21 22 // Getter / Setter は記載を省略

・Repositoryクラス

Java

1package ***; 2 3import org.springframework.data.jpa.repository.JpaRepository; 4import org.springframework.stereotype.Repository; 5 6import ***; 7 8@Repository 9public interface UserRepository extends JpaRepository<User, Long>{ 10}

・Repository呼出クラス

Java

1package ***; 2 3import org.springframework.beans.factory.annotation.Autowired; 4import org.springframework.http.MediaType; 5import org.springframework.web.bind.annotation.RequestBody; 6import org.springframework.web.bind.annotation.RequestMapping; 7import org.springframework.web.bind.annotation.RequestMethod; 8import org.springframework.web.bind.annotation.RestController; 9 10import ***.bean.User; 11import ***.repository.UserRepository; 12 13@RestController 14public class UsersControl { 15 16 @Autowired 17 UserRepository userRepository; 18 19 @RequestMapping(value="/v1/user", method=RequestMethod.POST, consumes=MediaType.APPLICATION_JSON_VALUE) 20 public void postUserInfo(@RequestBody User user) { 21 22 // ここでエラーが発生する 23 userRepository.save(user); 24 25 } 26}

・発生しているエラー

ERROR

1org.postgresql.util.PSQLException: ERROR: 列licenses0_.user_uidは存在しません 2 ポジション: 324 3 at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2433) ~[postgresql-42.2.2.jar:42.2.2] 4 at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2178) ~[postgresql-42.2.2.jar:42.2.2] 5 at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:306) ~[postgresql-42.2.2.jar:42.2.2] 6 at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:441) ~[postgresql-42.2.2.jar:42.2.2] 7 at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:365) ~[postgresql-42.2.2.jar:42.2.2] 8 at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:155) ~[postgresql-42.2.2.jar:42.2.2]

・テーブル構造

Postgres

1/* ユーザーテーブル */ 2CREATE TABLE users ( 3 uid VARCHAR NOT NULL -- ユーザーID 4 , photo_url VARCHAR -- 写真URL 5 , PRIMARY KEY (uid) 6); 7/* ユーザーテーブル */ 8CREATE TABLE user_licenses ( 9 license_id SERIAL NOT NULL -- ライセンスID 10 , uid VARCHAR NOT NULL -- ユーザーID 11 , authenticated BOOLEAN -- 認証済み 12 , PRIMARY KEY (license_id) 13 , FOREIGN KEY (uid) REFERENCES users(uid) 14);

大変基礎的なことで申し訳ございませんが、
ご教示よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/07/13 11:32

OneToMany/ManyToOne が対になってないからとかじゃないの?
yamashita_yuich

2018/07/13 11:44

添付するエラーメッセージが誤っていたので修正したのですが、出てきているメッセージは、子テーブル(user_licenses)に、指定された情報がありません、といったものだと考えています。ついては、まず子テーブルをINSERTし、そのあと親テーブルをINSETする処理を自動で実施することはできないかと考えています。
退会済みユーザー

退会済みユーザー

2018/07/13 11:46

テーブル構成見直してください。なエラーになったな
yamashita_yuich

2018/07/13 11:49

右記はテーブル構造です。/* ユーザーテーブル */ CREATE TABLE users ( uid VARCHAR NOT NULL -- ユーザーID , photo_url VARCHAR -- 写真URL , PRIMARY KEY (uid) ); /* ユーザーテーブル */ CREATE TABLE user_licenses ( license_id SERIAL NOT NULL -- ライセンスID , uid VARCHAR NOT NULL -- ユーザーID , authenticated BOOLEAN -- 認証済み , PRIMARY KEY (license_id) , FOREIGN KEY (uid) REFERENCES users(uid) );
yamashita_yuich

2018/07/13 11:51

上記読みづらいので、質問本文に記載させて頂きました。
guest

回答2

0

ベストアンサー

気になっていたので参考リンクを見ながらsave 1回でinsertできるよう検証してみました。

参考リンク曰く、UserからUserLicenseが参照でき、UserLicenseからUserが参照できる双方向リンクはあまり良いとはいえないそうですが、問題準拠で双方向リンクにしています。

環境

  • Java 1.8
  • Spring Boot 1.5.14
  • H2DB(mode=PostgreSQL)
  • Spring Data JPA

試験コード

java

1@RunWith(SpringRunner.class) 2@SpringBootTest 3public class DemoApplicationTests { 4 5 @Autowired 6 private UserRepository userRepository; 7 8 @Test 9 public void insertUser() { 10 User user = new User(); 11 user.setUId("user01"); 12 user.setPhotoUrl("/sample"); 13 14 userRepository.save(user); 15 16 User selectUser = userRepository.findOne("user01"); 17 assertEquals("/sample", selectUser.getPhotoUrl()); 18 assertEquals(0, selectUser.getLicenses().size()); 19 } 20 21 @Test 22 public void insertUserWithLicense() { 23 User user = new User(); 24 user.setUId("user02"); 25 user.setPhotoUrl("/sample"); 26 27 UserLicense ul = new UserLicense(); 28 ul.setUser(user); 29 ul.setAuthenticated(true); 30 user.getLicenses().add(ul); 31 32 userRepository.save(user); 33 34 User selectUser = userRepository.findOne("user02"); 35 assertEquals("/sample", selectUser.getPhotoUrl()); 36 assertEquals(1, selectUser.getLicenses().size()); 37 assertTrue(selectUser.getLicenses().get(0).isAuthenticated()); 38 } 39 40}

UserRepository の変更点

java

1// PK の型修正 2public interface UserRepository extends JpaRepository<User, String>{ 3}

User の変更点

java

1 // OneToMany アノテーションにパラメータを追加 2 @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "user") 3 private List<UserLicense> licenses = new ArrayList<>(); 4 5 // get/set uId を get/set UId に変更(自動生成すると引っかかる) 6 // 省略

UserLicense の変更点

java

1 // String uid の代わりに User を持つ 2 @ManyToOne(fetch = FetchType.EAGER) 3 @JoinColumn(name = "uid", nullable = false) 4 private User user;

参考リンク
OneToManyの参考リンク

投稿2018/07/15 17:07

TM3tmlab

総合スコア36

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yamashita_yuich

2019/01/19 09:32

レスホンスが大変遅くなり申し訳ございません。 上記プログラムで再度試してみました。 結果としてうまくいきました。ありがとうございます。 ただ、ページネーションの問題は大きいと感じました。 ページネーションのことも考えて(その他性能のことも考えて) 設計しないとデータが増えた場合に性能劣化の懸念があると感じました。 大変勉強になりました。ありがとうございます。
guest

0

1テーブルずつINSERTして最後にCommitするしかないのでしょうか?

何行INSERTしても構いませんが、親テーブルが先にINSERTされている必要があります。

org.postgresql.util.PSQLException: ERROR: 列licenses0_.user_uidは存在しません

外部キーが設定してありますから、親テーブル users の id が先に insert されていないと、子テーブル user_licenses の id は insert できません。
親テーブルを先にinsertしてから子テーブルをinsertすればcommitは後でも大丈夫です。

投稿2018/07/13 14:14

Orlofsky

総合スコア16415

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yamashita_yuich

2018/07/13 14:48

質問が伝わりづらかったと思いますが、トランザクションを張って、テーブルごとにINSERTを実施し、コミットすればできることは理解しています。しかし折角アノテーションでリレーション関係を表現しているので、1行でコミットできるとプログラムが簡潔になって良いと思っています。この方法を知りたいのです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問