การโพสต์การเชื่อมโยงทรัพยากรย่อย @OneToMany ใน Spring Data REST


103

ขณะนี้ฉันมีแอปพลิเคชัน Spring Boot โดยใช้ Spring Data REST ฉันมีนิติบุคคลโดเมนPostซึ่งมีความสัมพันธ์กับนิติบุคคลโดเมนอื่น@OneToMany Commentคลาสเหล่านี้มีโครงสร้างดังนี้:

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);
    }
}

ทุกอย่างดูเหมือนจะทำงานได้อย่างถูกต้อง เมื่อฉันเรียกใช้แอปพลิเคชันทุกอย่างดูเหมือนจะทำงานได้อย่างถูกต้อง ฉันสามารถโพสต์ออบเจ็กต์โพสต์ใหม่ได้http://localhost:8080/postsดังนี้:

ร่างกาย: {"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 เดียวกันฉันจะได้รับวิธี HTTP 405 ไม่อนุญาต

เป็นวิธีที่ถูกต้องในการสร้างสิ่งที่Commentทรัพยากรและเชื่อมโยงกับเรื่องนี้Post? ฉันต้องการหลีกเลี่ยงการโพสต์โดยตรงhttp://localhost:8080/commentsหากเป็นไปได้


9
7 วันต่อมาและยังไม่โชคดี หากใครทราบวิธีทำให้พฤติกรรมนี้ได้ผลโปรดแจ้งให้เราทราบ ขอบคุณ!
ccampo

คุณใช้ @RepositoryRestResource หรือคอนโทรลเลอร์หรือไม่ การดูโค้ดนั้นจะเป็นประโยชน์เช่นกัน
Magnus Lassi

ฉันใช้ 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สามารถเขียนได้ (ตัวอย่างเช่นโดยมี setter หรือ@JsonValueคำอธิบายประกอบ)
scheffield

1
สิ่งนี้ควรใช้กับคำขอแก้ไขเช่นเดียวกับการย้ายความคิดเห็นจากโพสต์หนึ่งไปยังอีกโพสต์หรือไม่
aycanadal

2
นี่อาจเป็นแนวทางที่ฉันชอบ (มาก) แต่ดูเหมือนจะไม่ได้ผลสำหรับฉัน :( มันสร้างความคิดเห็น แต่ไม่สร้างแถวในตารางความละเอียด (POST_COMMENTS) มีคำแนะนำเกี่ยวกับวิธีการแก้ไขอย่างไร
banncee

3
แนวทางจะเป็นอย่างไรสำหรับสถานการณ์เช่นกับหน่วยงานสถานที่และที่อยู่โดยสถานที่จัดงานต้องมีที่อยู่และที่อยู่ต้องเชื่อมโยงกับสถานที่ ฉันหมายถึง ... เพื่อหลีกเลี่ยงการสร้างที่อยู่เด็กกำพร้าซึ่งอาจไม่เคยถูกกำหนดให้กับสิ่งใด ๆ ? ฉันอาจจะผิด แต่แอปไคลเอนต์ไม่ควรรับผิดชอบในการรักษาความสอดคล้องภายในฐานข้อมูล ฉันไม่สามารถพึ่งพาแอปไคลเอนต์ที่สร้างที่อยู่แล้วกำหนดให้กับสถานที่ได้อย่างแน่นอน มีวิธีโพสต์ทรัพยากรย่อย (ในกรณีนี้คือเอนทิตีที่อยู่) ด้วยการสร้างทรัพยากรจริงหรือไม่เพื่อที่ฉันจะได้หลีกเลี่ยงความไม่สอดคล้องกัน
apostrophedottilde

2
ฉันพยายามทำสิ่งนี้ ( ดูที่นี่ ) แต่ด้วยเหตุผลบางประการมีเพียงทรัพยากรเท่านั้นที่สร้างขึ้นไม่ใช่การเชื่อมโยง
DisplayName

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. มอบหมายความคิดเห็นให้กับโพสต์โดยการออก A PUTให้กับ URI ของสมาคม

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

โปรดทราบว่าในขั้นตอนสุดท้ายตามข้อกำหนดของtext/uri-listคุณสามารถส่ง URI ที่ระบุความคิดเห็นหลายรายการโดยคั่นด้วยตัวแบ่งบรรทัดเพื่อกำหนดความคิดเห็นหลายรายการพร้อมกัน

หมายเหตุเพิ่มเติมเกี่ยวกับการตัดสินใจในการออกแบบทั่วไป ตัวอย่างโพสต์ / ความคิดเห็นมักเป็นตัวอย่างที่ดีสำหรับการสรุปรวมซึ่งหมายความว่าฉันจะหลีกเลี่ยงการอ้างอิงย้อนกลับจากCommentถึงPostและหลีกเลี่ยงCommentRepositoryอย่างสมบูรณ์ หากความคิดเห็นไม่มีวงจรชีวิตของตัวเอง (ซึ่งโดยปกติจะไม่อยู่ในความสัมพันธ์แบบการเรียบเรียง) คุณควรจะได้รับความคิดเห็นที่แสดงผลแบบอินไลน์โดยตรงและกระบวนการทั้งหมดในการเพิ่มและลบความคิดเห็นสามารถจัดการได้โดยใช้JSON Patch Spring Data REST ได้เพิ่มการสนับสนุนสำหรับสิ่งนั้นในผู้สมัครรุ่นล่าสุดสำหรับเวอร์ชัน 2.2 ที่กำลังจะมาถึง


4
สนใจที่นี่จากผู้มีสิทธิเลือกตั้งจำนวนมากเหตุผลของการโหวตคืออะไร;)
Oliver Drotbohm

3
ฉันไม่แน่ใจเกี่ยวกับผู้มีสิทธิเลือกตั้งที่ตกต่ำ ... ฉันไม่มีชื่อเสียงที่จะทำได้! เหตุผลที่ฉันไม่จำเป็นต้องใส่ความคิดเห็นไว้ในโพสต์เพราะพิจารณาสถานการณ์ (ไม่น่าจะเป็นไปได้) เมื่อฉันมีความคิดเห็นหลายพันรายการสำหรับโพสต์เดียว ฉันต้องการให้สามารถแบ่งหน้าคอลเลกชันของความคิดเห็นแทนที่จะได้รับทั้งกลุ่มทุกครั้งที่ฉันต้องการเข้าถึงเนื้อหาของโพสต์
ccampo

25
วิธีที่ง่ายที่สุดสำหรับผมที่จะแสดงความคิดเห็นที่จะทำให้ POST ไปยังlocalhost: 8080 / โพสต์ / 1 / ความคิดเห็น นี่เป็นวิธีที่ง่ายและมีความหมายที่สุดไม่ใช่หรือ? และในขณะเดียวกันคุณยังควรมีที่เก็บความคิดเห็นเฉพาะ สปริงหรือมาตรฐาน HAL ไม่อนุญาตให้ทำเช่นนี้?
aycanadal

4
@OliverGierke นี่ยังคงเป็นวิธีที่แนะนำ / วิธีเดียวที่จะทำสิ่งนี้หรือไม่? จะเกิดอะไรขึ้นถ้าเด็กไม่เป็นโมฆะ ( @JoinColumn(nullable=false))? จะเป็นไปไม่ได้ที่จะโพสต์ลูกก่อนจากนั้น PUT / PATCH การเชื่อมโยงหลัก
ลิ้ม

2
มีคำแนะนำในการใช้ api ที่สร้างขึ้นโดยใช้ข้อมูลสปริงหรือไม่ ฉันใช้ googled เป็นเวลา 2 ชั่วโมงและไม่พบอะไรเลย ขอบคุณ!
Skeeve

2

มี 2 ​​ประเภทของการเชื่อมโยงการทำแผนที่และองค์ประกอบ ในกรณีของการเชื่อมโยงเราใช้แนวคิดตารางเข้าร่วมเช่น

พนักงาน - 1 ถึง n-> แผนก

ดังนั้น 3 ตารางจะถูกสร้างขึ้นในกรณีของ Association Employee, Department, Employee_Department

คุณต้องสร้าง EmployeeRepository ในโค้ดของคุณเท่านั้น นอกเหนือจากการทำแผนที่ควรเป็นเช่นนั้น:

class EmployeeEntity{

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

   }

}

Depatment Entity จะไม่มีการแมปคีย์ forign ใด ๆ ... ดังนั้นเมื่อคุณจะลองใช้คำขอ POST เพื่อเพิ่มพนักงานกับแผนกในคำขอ json เดียวจะถูกเพิ่ม ....


1

ฉันต้องเผชิญกับสถานการณ์เดียวกันและฉันต้องลบคลาสพื้นที่เก็บข้อมูลสำหรับเอนทิตีย่อยเนื่องจากฉันใช้การแมปแบบหนึ่งต่อหลายรายการและดึงข้อมูลผ่านเอนทิตีหลักเอง ตอนนี้ฉันได้รับคำตอบทั้งหมดพร้อมข้อมูล


1
สิ่งที่คุณพูดถึงนี้อาจทำได้ง่ายๆด้วยการคาดการณ์
kboom

0

สำหรับการแมป oneToMany เพียงแค่สร้าง POJO สำหรับคลาสนั้นที่คุณต้องการแมปและคำอธิบายประกอบ @OneToMany กับมันและภายในจะแมปกับรหัสตารางนั้น

นอกจากนี้คุณต้องใช้อินเทอร์เฟซที่ต่ออนุกรมได้กับคลาสที่คุณกำลังดึงข้อมูล

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.