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

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

ただいまの
回答率

90.52%

  • PostgreSQL

    1068questions

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

  • Spring Boot

    501questions

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

  • Java Persistence API

    6questions

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

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

受付中

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 316

baseballyama

score 241

  1. 質問概要

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

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

  1. 該当のソースコード

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

package ***;

import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "users")
public class User {

    @Id
    @Column(name = "uid")
    private String uId;

    @Column(name = "photo_url")
    private String photoUrl;

    @OneToMany
    @JoinColumn(name = "uid", nullable = true)
    private List<UserLicense> licenses;

       // Getter / Setter は記載を省略

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

package ***;

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

@Entity
@Table(name = "user_licenses")
public class UserLicnse {

    @Id
    @Column(name = "license_id")
    private int licenseId;

    @Column(name = "uid")
    private String uId;

    @Column(name = "authenticated")
    private boolean authenticated;

       // Getter / Setter は記載を省略

・Repositoryクラス

package ***;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import ***;

@Repository
public interface UserRepository extends JpaRepository<User, Long>{
}

・Repository呼出クラス

package ***;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import ***.bean.User;
import ***.repository.UserRepository;

@RestController
public class UsersControl {

    @Autowired
    UserRepository userRepository;

    @RequestMapping(value="/v1/user", method=RequestMethod.POST, consumes=MediaType.APPLICATION_JSON_VALUE)
    public void postUserInfo(@RequestBody User user) {

                // ここでエラーが発生する
        userRepository.save(user);

    }
}

・発生しているエラー

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

・テーブル構造

/* ユーザーテーブル */
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)
);

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • asahina1979

    2018/07/13 20:46

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

    キャンセル

  • baseballyama

    2018/07/13 20: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) );

    キャンセル

  • baseballyama

    2018/07/13 20:51

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

    キャンセル

回答 2

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 23:48

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

    キャンセル

0

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

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

 環境

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

 試験コード

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {

  @Autowired
  private UserRepository userRepository;

  @Test
  public void insertUser() {
    User user = new User();
    user.setUId("user01");
    user.setPhotoUrl("/sample");

    userRepository.save(user);

    User selectUser = userRepository.findOne("user01");
    assertEquals("/sample", selectUser.getPhotoUrl());
    assertEquals(0, selectUser.getLicenses().size());
  }

  @Test
  public void insertUserWithLicense() {
    User user = new User();
    user.setUId("user02");
    user.setPhotoUrl("/sample");

    UserLicense ul = new UserLicense();
    ul.setUser(user);
    ul.setAuthenticated(true);
    user.getLicenses().add(ul);

    userRepository.save(user);

    User selectUser = userRepository.findOne("user02");
    assertEquals("/sample", selectUser.getPhotoUrl());
    assertEquals(1, selectUser.getLicenses().size());
    assertTrue(selectUser.getLicenses().get(0).isAuthenticated());
  }

}

 UserRepository の変更点

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

 User の変更点

  // OneToMany アノテーションにパラメータを追加
  @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "user")
  private List<UserLicense> licenses = new ArrayList<>();

  // get/set uId を get/set UId に変更(自動生成すると引っかかる)
  // 省略

 UserLicense の変更点

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 90.52%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • PostgreSQL

    1068questions

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

  • Spring Boot

    501questions

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

  • Java Persistence API

    6questions

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