Spring Data RESTで@OneToManyサブリソース関連付けをPOSTする


103

現在、Spring Data RESTを使用したSpring Bootアプリケーションがあります。別のドメインエンティティとの関係をPost持つドメインエンティティがあります。これらのクラスは次のように構成されています。@OneToManyComment

Post.java:

@Entity
public class Post {

    @Id
    @GeneratedValue
    private long id;
    private String author;
    private String content;
    private String title;

    @OneToMany
    private List<Comment> comments;

    // Standard getters and setters...
}

Comment.java:

@Entity
public class Comment {

    @Id
    @GeneratedValue
    private long id;
    private String author;
    private String content;

    @ManyToOne
    private Post post;

    // Standard getters and setters...
}

これらのSpring Data REST JPAリポジトリは、の基本的な実装ですCrudRepository

PostRepository.java:

public interface PostRepository extends CrudRepository<Post, Long> { }

CommentRepository.java:

public interface CommentRepository extends CrudRepository<Comment, Long> { }

アプリケーションのエントリポイントは、標準のシンプルなSpring Bootアプリケーションです。すべてが構成済みの在庫です。

Application.java

@Configuration
@EnableJpaRepositories
@Import(RepositoryRestMvcConfiguration.class)
@EnableAutoConfiguration
public class Application {

    public static void main(final String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

すべてが正しく機能しているようです。アプリケーションを実行すると、すべてが正しく動作しているように見えます。新しいPostオブジェクトを次のhttp://localhost:8080/postsようにPOSTできます。

体: {"author":"testAuthor", "title":"test", "content":"hello world"}

の結果http://localhost:8080/posts/1

{
    "author": "testAuthor",
    "content": "hello world",
    "title": "test",
    "_links": {
        "self": {
            "href": "http://localhost:8080/posts/1"
        },
        "comments": {
            "href": "http://localhost:8080/posts/1/comments"
        }
    }
}

ただし、GETを実行するとhttp://localhost:8080/posts/1/comments、空のオブジェクトが{}返され、同じURIにコメントをPOSTしようとすると、HTTP 405メソッドが許可されません。

Commentリソースを作成してこれに関連付ける正しい方法は何Postですか?http://localhost:8080/commentsできれば直接POSTするのは避けたいです。


9
7日後、まだ運がありません。誰かがこの動作を機能させる方法を知っている場合は、私に知らせてください。ありがとう!
ccampo 2014

@RepositoryRestResourceまたはコントローラーを使用していますか?そのコードも確認すると参考になります。
Magnus Lassi 2014

私はSpring boot data restを使用しています、それは私のために働きましたhttp://stackoverflow.com/questions/37902946/add-item-to-the-collection-with-foreign-key-via-rest-call
Taimur

回答:


47

最初にコメントを投稿する必要があります。コメントの投稿中に、関連投稿エンティティを作成できます。

以下のようになります。

http://{server:port}/comment METHOD:POST

{"author":"abc","content":"PQROHSFHFSHOFSHOSF", "post":"http://{server:port}/post/1"}

そしてそれは完全にうまく働きます。


2
これでうまくいきました。author.postが書き込み可能であることを確認してください(たとえば、セッターまたは@JsonValue注釈を付けることにより)
scheffield

1
これは、コメントをある投稿から別の投稿に移動する場合のように、パッチリクエストでも機能しますか?
aycanadal 2015年

2
これは私の(大雑把に)推奨されるアプローチですが、私にはうまくいかないようです。:(コメントを作成しますが、解決テーブル(POST_COMMENTS)に行を作成しません。解決方法に関する提案はありますか?
banncee '25 / 10/25

3
シナリオにはどのようなアプローチがありますか。たとえば、会場と住所エンティティの場合、会場には住所が必要であり、住所は会場に関連付けられている必要があります。つまり、何にも割り当てられない可能性がある孤立したアドレスを作成しないようにするためですか?たぶん私は間違っているかもしれませんが、クライアントアプリはデータベース内の一貫性を維持する責任がありません クライアントアプリでアドレスを作成してから、会場に確実に割り当てることはできません。実際のリソースを作成してサブリソース(この場合はアドレスエンティティ)をPOSTして、不整合を回避する方法はありますか?
アポストロフェドチルド

2
私はこれを試みます(ここを参照)が、何らかの理由で、関連付けではなくリソースのみが作成されます。
displayname '19 / 11/17

55

投稿URI、つまり関連リソースのURI($association_uri以下にあると見なされます)がすでに発見されているとすると、通常は次の手順を実行します。

  1. コメントを管理するコレクションリソースを見つけます。

    curl -X GET http://localhost:8080
    
    200 OK
    { _links : {
        comments : { href : "…" },
        posts :  { href : "…" }
      }
    }
  2. リソースへのcommentsリンクとPOSTデータに従ってください:

    curl -X POST -H "Content-Type: application/json" $url 
    {  // your payload // … }
    
    201 Created
    Location: $comment_url
  3. PUT関連付けURIにa を発行して、コメントを投稿に割り当てます。

    curl -X PUT -H "Content-Type: text/uri-list" $association_url
    $comment_url
    
    204 No Content

最後のステップでは、の仕様に従って、text/uri-listコメントを識別する複数のURIを改行で区切って送信し、一度に複数のコメントを割り当てることができることに注意してください。

一般的な設計上の決定に関するいくつかのメモ。投稿/コメントの例は通常、集計の優れた例です。つまり、Commentからへの逆参照をPost避け、CommentRepository完全に回避します。コメント自体にライフサイクルがない場合(通常はコンポジションスタイルの関係ではありません)、コメントを直接インラインでレンダリングします。コメントを追加および削除するプロセス全体は、以下を使用して処理できます。JSONパッチ。Spring Data RESTは、次のバージョン2.2の最新リリース候補でのサポートを追加ました。


4
反対投票者からここに興味がある、投票の理由は何だった;)。
Oliver Drotbohm 2014

3
反対票を投じているかどうかはわかりません...評判すらありません。投稿にインラインでコメントを付けるのが必ずしも好きではない理由は、1つの投稿に対して何千ものコメントがある場合の(ありそうもない)シナリオを検討するためです。投稿のコンテンツにアクセスするたびにコメント全体を取得するのではなく、コメントのコレクションにページ番号を付けられるようにしたいと思います。
ccampo 2014

25
コメントを投稿する最も直感的な方法は、localhost:8080 / posts / 1 / commentsに POSTを実行することです。それを行う最も簡単で意味のある方法ではありませんか?同時に、専用のコメントリポジトリを用意することもできます。これを許可しないのは春またはHAL標準ですか?
aycanadal

4
@OliverGierkeこれはまだこれを行うための推奨される/唯一の方法ですか?子供がnull可能ではない場合(@JoinColumn(nullable=false))はどうなりますか?最初に子をPOSTし、次に親の関連付けをPUT / PATCHすることはできません。
JW Lim

2
Spring Data Restで作成されたAPIを使用するためのガイドはありますか?2時間グーグル検索してみましたが何も見つかりませんでした。ありがとうございました!
Skeeve、2016年

2

マッピングの関連付けと構成には2つのタイプがあります。関連付けの場合、次のような結合テーブルの概念を使用しました

従業員--1からn->部門

したがって、Association Employee、Department、Employee_Departmentの場合、3つのテーブルが作成されます

コードでEmployeeRepositoryを作成する必要があるだけです。そのマッピングは別として、次のようにする必要があります。

class EmployeeEntity{

@OnetoMany(CascadeType.ALL)
   private List<Department> depts {

   }

}

Depatment Entityには、forignキーのマッピングが含まれていません...したがって、単一のjsonリクエストでDepartmentを使用してEmployeeを追加するPOSTリクエストを試行すると、追加されます。


1

同じシナリオに直面し、1対多のマッピングを使用してデータをメインエンティティ自体にプルしたため、サブエンティティのリポジトリクラスを削除する必要がありました。今、私はすべての応答をデータで取得しています。


1
あなたが話しているこのことは、予測で簡単に行われるかもしれません
kboom

0

oneToManyマッピングの場合、マップするクラスのPOJOを作成し、それに@OneToManyアノテーションを作成するだけで、内部的にそのTable idにマッピングされます。

また、データを取得するクラスにSerializableインターフェースを実装する必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.