Memposting asosiasi sub-resource @OneToMany di Spring Data REST

103

Saat ini saya memiliki aplikasi Spring Boot menggunakan Spring Data REST. Saya memiliki entitas domain Postyang memiliki @OneToManyhubungan dengan entitas domain lain Comment,. Kelas-kelas ini disusun sebagai berikut:

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...
}

Repositori JPA Spring Data REST mereka adalah implementasi dasar dari CrudRepository:

PostRepository.java:

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

CommentRepository.java:

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

Titik masuk aplikasi adalah aplikasi Spring Boot standar dan sederhana. Semuanya sudah dikonfigurasi stok.

Application.java

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

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

Semuanya tampak bekerja dengan benar. Ketika saya menjalankan aplikasi, semuanya tampak bekerja dengan benar. Saya dapat POST objek Post baru untuk http://localhost:8080/postsmenyukainya:

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

Hasil di 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"
        }
    }
}

Namun, ketika saya melakukan GET di http://localhost:8080/posts/1/commentssaya mendapatkan objek kosong {}dikembalikan, dan jika saya mencoba untuk mengirim komentar ke URI yang sama, saya mendapatkan Metode HTTP 405 Tidak Diizinkan.

Apa cara yang benar untuk membuat Commentsumber daya dan mengaitkannya dengan ini Post? Saya ingin menghindari POST langsung ke http://localhost:8080/commentsjika memungkinkan.

ccampo
sumber
9
7 hari kemudian dan masih belum beruntung. Jika ada yang tahu cara agar perilaku ini berhasil, beri tahu saya. Terima kasih!
ccampo
apakah Anda menggunakan @RepositoryRestResource atau pengontrol? Akan sangat membantu untuk melihat kode itu juga.
Magnus Lassi
Saya menggunakan istirahat data boot Musim Semi, Ini berfungsi untuk saya http://stackoverflow.com/questions/37902946/add-item-to-the-collection-with-foreign-key-via-rest-call
Taimur

Jawaban:

47

Anda harus memposting komentar terlebih dahulu dan saat memposting komentar Anda dapat membuat entitas posting asosiasi.

Ini akan terlihat seperti di bawah ini:

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

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

dan itu akan bekerja dengan baik.

Chetan Kokil
sumber
2
Ini berhasil untuk saya. Pastikan saja author.postdapat ditulisi (misalnya dengan memiliki penyetel atau @JsonValuepenjelasan)
scheffield
1
Haruskah ini juga bekerja dengan permintaan tambalan seperti dalam memindahkan komentar dari satu posting ke posting lain?
aycanadal
2
Ini akan menjadi pendekatan yang saya (sangat) sukai, tetapi tampaknya tidak berhasil untuk saya. :( Ini membuat Komentar, tetapi tidak membuat baris dalam tabel resolusi (POST_COMMENTS). Adakah saran tentang cara menyelesaikannya?
banncee
3
Apa pendekatan yang digunakan untuk skenario, misalnya dengan entitas Tempat dan Alamat, di mana tempat harus memiliki Alamat dan alamat HARUS dikaitkan dengan Tempat? Maksud saya ... untuk menghindari membuat alamat yatim piatu yang mungkin tidak pernah ditugaskan ke apapun? Mungkin saya salah, tetapi aplikasi klien HARUS PERNAH bertanggung jawab menjaga konsistensi dalam database. Saya tidak dapat mengandalkan aplikasi klien untuk membuat Alamat dan kemudian menetapkannya ke Tempat. Apakah ada cara untuk POST sub-sumber daya (dalam hal ini entitas Alamat) dengan pembuatan sumber daya yang sebenarnya sehingga saya dapat menghindari ketidakkonsistenan ??
apostrophedottilde
2
Saya mencoba melakukan ini ( lihat di sini ) tetapi untuk beberapa alasan hanya sumber daya, bukan pengaitan, yang dibuat.
tampilan
55

Dengan asumsi Anda telah menemukan URI posting dan dengan demikian URI sumber daya asosiasi (dianggap sebagai $association_uriberikut), biasanya dibutuhkan langkah-langkah berikut:

  1. Temukan sumber daya koleksi yang mengelola komentar:

    curl -X GET http://localhost:8080
    
    200 OK
    { _links : {
        comments : { href : "…" },
        posts :  { href : "…" }
      }
    }
  2. Ikuti commentstautan dan POSTdata Anda ke sumber daya:

    curl -X POST -H "Content-Type: application/json" $url 
    {  // your payload // … }
    
    201 Created
    Location: $comment_url
  3. Tetapkan komentar ke postingan dengan mengeluarkan a PUTke URI pengaitan.

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

Perhatikan, bahwa pada langkah terakhir, sesuai spesifikasi text/uri-list, Anda dapat mengirimkan beberapa URI yang mengidentifikasi komentar yang dipisahkan oleh jeda baris untuk menetapkan beberapa komentar sekaligus.

Beberapa catatan lagi tentang keputusan desain umum. Contoh posting / komentar biasanya merupakan contoh yang bagus untuk agregat, yang berarti saya akan menghindari referensi balik dari Commentke Postdan juga menghindari CommentRepositorysepenuhnya. Jika komentar tidak memiliki siklus prosesnya sendiri (yang biasanya tidak ada dalam hubungan gaya komposisi) Anda lebih suka membuat komentar tersebut dirender secara langsung dan seluruh proses penambahan dan penghapusan komentar dapat ditangani dengan menggunakan JSON Patch . Spring Data REST telah menambahkan dukungan untuk itu di kandidat rilis terbaru untuk versi 2.2 mendatang.

Oliver Drotbohm
sumber
4
Tertarik ke sini dari pemilih bawah, apa alasan pemilihannya;).
Oliver Drotbohm
3
Saya tidak yakin dengan pemilih yang down ... Saya bahkan tidak punya reputasi untuk melakukannya! Alasan saya tidak suka meletakkan komentar sejajar dengan posting adalah karena mempertimbangkan skenario (tidak mungkin) ketika saya memiliki ribuan komentar untuk satu posting. Saya ingin dapat memberi nomor pada kumpulan komentar daripada mendapatkan semuanya setiap kali saya ingin mengakses konten kiriman.
ccampo
25
Cara paling intuitif bagi saya untuk mengirim komentar adalah dengan melakukan POSTING ke localhost: 8080 / posts / 1 / comments . Bukankah ini cara yang paling sederhana dan paling berarti untuk melakukannya? Dan pada saat yang sama, Anda masih bisa memiliki repositori komentar khusus. Apakah standar musim semi atau HAL yang tidak mengizinkan ini?
aycanadal
4
@OliverGierke Apakah ini masih cara / satu-satunya yang direkomendasikan untuk melakukan ini? Bagaimana jika anak tersebut bukan-nullable ( @JoinColumn(nullable=false))? Tidak mungkin untuk POST anak pertama, kemudian PUT / PATCH asosiasi induk.
JW Lim
2
Apakah ada panduan untuk menggunakan api yang dibuat dengan pegas data rest? Saya telah mencarinya di Google selama 2 jam dan tidak menemukan apa pun. Terima kasih!
Skeeve
2

Ada 2 jenis Asosiasi dan Komposisi pemetaan. Dalam kasus asosiasi kami menggunakan konsep tabel gabung seperti

Karyawan - 1 sampai n-> Departemen

Jadi 3 tabel akan dibuat dalam kasus Asosiasi Karyawan, Departemen, Departemen_Departemen

Anda hanya perlu membuat EmployeeRepository dalam kode Anda. Selain itu pemetaan harus seperti itu:

class EmployeeEntity{

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

   }

}

Entitas Depatment tidak akan berisi pemetaan apa pun untuk kunci forign ... jadi sekarang ketika Anda akan mencoba permintaan POST untuk menambahkan Karyawan dengan Departemen dalam permintaan json tunggal maka itu akan ditambahkan ....

Naveen Goyal
sumber
1

Saya menghadapi skenario yang sama dan saya harus menghapus kelas repositori untuk sub entitas karena saya telah menggunakan satu ke banyak pemetaan dan menarik data melalui entitas utama itu sendiri. Sekarang saya mendapatkan seluruh respons dengan data.

Selva
sumber
1
Hal yang Anda bicarakan ini dapat dengan mudah dilakukan dengan proyeksi
kboom
0

Untuk pemetaan oneToMany, cukup buat POJO untuk kelas yang ingin Anda Peta, dan anotasi @OneToMany padanya, dan secara internal akan memetakannya ke ID Tabel tersebut.

Selain itu, Anda perlu mengimplementasikan antarmuka Serializable ke kelas tempat Anda mengambil Data.

Chaurasia cerah
sumber