ĐĂNG liên kết tài nguyên con @OneToMany trong Spring Data REST


103

Hiện tại tôi có một ứng dụng Spring Boot sử dụng Spring Data REST. Tôi có một thực thể miền Post@OneToManymối quan hệ với một thực thể miền khác Comment,. Các lớp này được cấu trúc như sau:

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

Kho lưu trữ Spring Data REST JPA của họ là các triển khai cơ bản của CrudRepository:

PostRepository.java:

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

CommentRepository.java:

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

Điểm nhập ứng dụng là một ứng dụng Spring Boot tiêu chuẩn, đơn giản. Tất cả mọi thứ được cấu hình cổ phiếu.

Application.java

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

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

Mọi thứ dường như hoạt động chính xác. Khi tôi chạy ứng dụng, mọi thứ dường như hoạt động chính xác. Tôi có thể ĐĂNG một đối tượng Bài đăng mới để http://localhost:8080/poststhích như vậy:

Thân hình: {"author":"testAuthor", "title":"test", "content":"hello world"}

Kết quả tại 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"
        }
    }
}

Tuy nhiên, khi tôi thực hiện GET, http://localhost:8080/posts/1/commentstôi nhận được một đối tượng trống được {}trả về và nếu tôi cố gắng ĐĂNG nhận xét lên cùng một URI, tôi nhận được Phương thức HTTP 405 Không được phép.

Cách chính xác để tạo một Commenttài nguyên và kết hợp nó với nó là Postgì? Tôi muốn tránh ĐĂNG trực tiếp http://localhost:8080/commentsnếu có thể.


9
7 ngày sau và vẫn không may mắn. Nếu ai đó biết cách để làm cho hành vi này hoạt động, vui lòng cho tôi biết. Cảm ơn!
ccampo

bạn đang sử dụng @RepositoryRestResource hay bộ điều khiển? Nó cũng sẽ hữu ích để xem mã đó.
Magnus Lassi

Tôi đang sử dụng phần còn lại dữ liệu khởi động Spring, Nó hoạt động với tôi http://stackoverflow.com/questions/37902946/add-item-to-the-collection-with-foreign-key-via-rest-call
Taimur

Câu trả lời:


47

Bạn phải đăng nhận xét trước và trong khi đăng nhận xét, bạn có thể tạo một thực thể bài đăng liên kết.

Nó sẽ trông giống như dưới đây:

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

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

và nó sẽ hoạt động hoàn toàn tốt.


2
Điều này đã làm việc cho tôi. Chỉ cần đảm bảo rằng author.post@JsonValue
tệp

1
Điều này cũng có nên hoạt động với một yêu cầu vá như khi chuyển nhận xét từ bài đăng này sang bài đăng khác không?
aycanadal

2
Đây sẽ là cách tiếp cận ưa thích (rất lớn) của tôi, nhưng dường như nó không hiệu quả với tôi. :( Nó tạo ra các bình luận, nhưng không tạo ra các hàng trong bảng độ phân giải (POST_COMMENTS) Bất kỳ đề xuất về cách giải quyết.?
banncee

3
Cách tiếp cận sẽ như thế nào đối với một tình huống, ví dụ với các thực thể Địa điểm và Địa chỉ, trong đó một địa điểm phải có Địa chỉ và địa chỉ PHẢI được liên kết với Địa điểm? Ý tôi là ... để tránh tạo một địa chỉ mồ côi có thể không bao giờ được gán cho bất cứ thứ gì? Có thể tôi sai, nhưng ứng dụng khách KHÔNG BAO GIỜ phải chịu trách nhiệm duy trì tính nhất quán trong cơ sở dữ liệu. Tôi không thể dựa vào ứng dụng khách tạo Địa chỉ và sau đó chắc chắn chỉ định cho Địa điểm. Có cách nào để ĐĂNG tài nguyên con (trong trường hợp này là thực thể Địa chỉ) với việc tạo tài nguyên thực tế để tôi có thể tránh sự mâu thuẫn không ??
dấu nháy đơn,

2
Tôi cố gắng thực hiện việc này ( xem tại đây ) nhưng vì lý do nào đó mà chỉ tài nguyên, không phải liên kết, được tạo.
hiển thị

55

Giả sử bạn đã phát hiện ra URI của bài đăng và do đó là URI của tài nguyên liên kết (được coi là $association_uritrong phần sau), nó thường thực hiện các bước sau:

  1. Khám phá các nhận xét quản lý tài nguyên thu thập:

    curl -X GET http://localhost:8080
    
    200 OK
    { _links : {
        comments : { href : "…" },
        posts :  { href : "…" }
      }
    }
  2. Theo commentsliên kết và POSTdữ liệu của bạn đến tài nguyên:

    curl -X POST -H "Content-Type: application/json" $url 
    {  // your payload // … }
    
    201 Created
    Location: $comment_url
  3. Gán nhận xét cho bài đăng bằng cách cấp PUTcho URI liên kết.

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

Lưu ý rằng trong bước cuối cùng, theo đặc điểm kỹ thuật của text/uri-list, bạn có thể gửi nhiều URI xác định nhận xét được phân tách bằng dấu ngắt dòng để gán nhiều nhận xét cùng một lúc.

Thêm một vài lưu ý về các quyết định thiết kế chung. Ví dụ về bài đăng / nhận xét thường là một ví dụ tuyệt vời cho tổng hợp, điều đó có nghĩa là tôi sẽ tránh tham chiếu ngược từ Commentđến Postvà cũng tránh CommentRepositoryhoàn toàn. Nếu các nhận xét không có vòng đời riêng của chúng (mà chúng thường không có trong mối quan hệ kiểu bố cục), bạn muốn nhận các nhận xét được hiển thị trực tiếp và toàn bộ quá trình thêm và xóa nhận xét có thể được xử lý bằng cách sử dụng Bản vá JSON . Spring Data REST đã thêm hỗ trợ cho điều đó trong ứng cử viên phát hành mới nhất cho phiên bản 2.2 sắp tới.


4
Từ cử tri xuống đây quan tâm, lý do bỏ phiếu là gì;).
Oliver Drotbohm

3
Tôi không chắc về số cử tri xuống ... Tôi thậm chí không có danh tiếng để làm điều đó! Lý do tôi không nhất thiết phải thích đưa bình luận vào nội tuyến bài đăng là vì hãy xem xét kịch bản (không chắc) khi tôi có hàng nghìn bình luận cho một bài đăng. Tôi muốn có thể phân loại bộ sưu tập các bình luận thay vì lấy toàn bộ chúng mỗi khi tôi muốn truy cập nội dung của bài đăng.
ccampo

25
Cách trực quan nhất để tôi đăng nhận xét là thực hiện ĐĂNG lên localhost: 8080 / posts / 1 / comments . Đó không phải là cách đơn giản và ý nghĩa nhất để làm điều đó sao? Và đồng thời, bạn vẫn có thể có một kho bình luận chuyên dụng. Có phải nó là tiêu chuẩn lò xo hoặc HAL không cho phép điều này?
aycanadal

4
@OliverGierke Đây có còn là cách được khuyến nghị / duy nhất để thực hiện việc này không? Điều gì sẽ xảy ra nếu con không-nullable ( @JoinColumn(nullable=false))? Trước tiên sẽ không thể ĐĂNG con, sau đó ĐĂNG / ĐÓNG liên kết mẹ.
JW Lim

2
Có hướng dẫn nào để sử dụng api được tạo với phần còn lại dữ liệu mùa xuân không? Tôi đã truy cập nó trong 2 giờ và không tìm thấy gì. Cảm ơn bạn!
Skeeve

2

Có 2 loại bản đồ Hiệp hội và Thành phần. Trong trường hợp liên kết, chúng tôi đã sử dụng khái niệm bảng tham gia như

Nhân viên - 1 đến n-> Bộ phận

Vì vậy, 3 bảng sẽ được tạo trong trường hợp Nhân viên Hiệp hội, Bộ phận, Nhân viên_phân khu

Bạn chỉ cần tạo mã EmployeeRepository trong mã của bạn. Ngoài ánh xạ đó nên như vậy:

class EmployeeEntity{

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

   }

}

Depatment Entity sẽ không chứa bất kỳ ánh xạ nào cho khóa forign ... vì vậy bây giờ khi bạn thử yêu cầu ĐĂNG để thêm Nhân viên với Phòng trong một yêu cầu json duy nhất thì nó sẽ được thêm vào ....


1

Tôi phải đối mặt với tình huống tương tự và tôi phải xóa lớp kho lưu trữ cho thực thể con vì tôi đã sử dụng một lớp cho nhiều ánh xạ và kéo dữ liệu qua chính thực thể chính. Bây giờ tôi đang nhận được toàn bộ phản hồi với dữ liệu.


1
Điều này mà bạn nói chuyện về có thể dễ dàng thực hiện với dự báo
KBOOM

0

Đối với ánh xạ oneToMany, chỉ cần tạo một POJO cho lớp mà bạn muốn Ánh xạ và chú thích @OneToMany cho nó, và bên trong nó sẽ ánh xạ nó với id Bảng đó.

Ngoài ra, bạn cần triển khai giao diện Serializable cho lớp bạn đang truy xuất Dữ liệu.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.