POSTEN einer @ OneToMany-Subressourcenzuordnung in Spring Data REST

103

Derzeit habe ich eine Spring Boot-Anwendung, die Spring Data REST verwendet. Ich habe eine Domänenentität, Postdie die @OneToManyBeziehung zu einer anderen Domänenentität hat Comment. Diese Klassen sind wie folgt aufgebaut:

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

Ihre Spring Data REST JPA-Repositorys sind grundlegende Implementierungen von CrudRepository:

PostRepository.java:

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

CommentRepository.java:

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

Der Anwendungseinstiegspunkt ist eine einfache Standard-Spring-Boot-Anwendung. Alles ist Lager konfiguriert.

Application.java

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

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

Alles scheint richtig zu funktionieren. Wenn ich die Anwendung ausführe, scheint alles korrekt zu funktionieren. Ich kann ein neues Post-Objekt http://localhost:8080/postsPOSTEN, um es so zu mögen:

Körper: {"author":"testAuthor", "title":"test", "content":"hello world"}

Ergebnis bei 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"
        }
    }
}

Wenn ich jedoch ein GET bei ausführe http://localhost:8080/posts/1/comments, wird ein leeres Objekt {}zurückgegeben, und wenn ich versuche, einen Kommentar an denselben URI zu senden, wird eine HTTP 405-Methode nicht zulässig angezeigt.

Wie kann eine CommentRessource richtig erstellt und damit verknüpft werden Post? Ich möchte es vermeiden, http://localhost:8080/commentswenn möglich direkt zu posten .

ccampo
quelle
9
7 Tage später und immer noch kein Glück. Wenn jemand einen Weg kennt, um dieses Verhalten zum Laufen zu bringen, lassen Sie es mich bitte wissen. Vielen Dank!
Ccampo
Verwenden Sie @RepositoryRestResource oder einen Controller? Es wäre hilfreich, auch diesen Code zu sehen.
Magnus Lassi
Ich verwende Spring Boot Data Rest. Es hat bei mir funktioniert. Http://stackoverflow.com/questions/37902946/add-item-to-the-collection-with-foreign-key-via-rest-call
Taimur

Antworten:

47

Sie müssen zuerst den Kommentar veröffentlichen, und während Sie den Kommentar veröffentlichen, können Sie eine Entitätsbeitragsentität erstellen.

Es sollte ungefähr so ​​aussehen:

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

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

und es wird perfekt funktionieren.

Chetan Kokil
quelle
2
Das hat bei mir funktioniert. author.post@JsonValue
Stellen Sie
1
Sollte dies auch mit einer Patch-Anfrage funktionieren, wie beim Verschieben des Kommentars von einem Beitrag in einen anderen?
Aycanadal
2
Dies wäre mein (sehr) bevorzugter Ansatz, aber er scheint für mich nicht zu funktionieren. :( Es erstellt den Kommentar, aber nicht die Zeile in der Auflösungstabelle (POST_COMMENTS). Irgendwelche Vorschläge zur Lösung?
Banncee
3
Wie würde der Ansatz für ein Szenario aussehen, z. B. bei Entitäten für Veranstaltungsort und Adresse, bei denen ein Veranstaltungsort eine Adresse haben muss und eine Adresse einem Veranstaltungsort zugeordnet sein muss? Ich meine ... um zu vermeiden, dass eine verwaiste Adresse erstellt wird, die möglicherweise nie zugewiesen wird? Vielleicht irre ich mich, aber die Client-App sollte niemals dafür verantwortlich sein, die Konsistenz innerhalb der Datenbank aufrechtzuerhalten. Ich kann mich nicht darauf verlassen, dass die Client-App eine Adresse erstellt und diese dann definitiv einem Veranstaltungsort zuweist. Gibt es eine Möglichkeit, die Unterressource (in diesem Fall die Adressentität) mit der Erstellung der eigentlichen Ressource zu POSTEN, damit Inkonsistenzen vermieden werden können?
Apostrophedottilde
2
Ich versuche dies zu tun ( siehe hier ), aber aus irgendeinem Grund wird nur die Ressource erstellt, nicht die Zuordnung.
Anzeigename
55

Angenommen, Sie haben den Post-URI und damit den URI der Zuordnungsressource bereits erkannt (wird $association_uriim Folgenden berücksichtigt), werden im Allgemeinen die folgenden Schritte ausgeführt:

  1. Entdecken Sie die Kommentare zur Verwaltung von Sammlungsressourcen:

    curl -X GET http://localhost:8080
    
    200 OK
    { _links : {
        comments : { href : "…" },
        posts :  { href : "…" }
      }
    }
  2. Folgen Sie dem commentsLink und POSTIhren Daten zur Ressource:

    curl -X POST -H "Content-Type: application/json" $url 
    {  // your payload // … }
    
    201 Created
    Location: $comment_url
  3. Weisen Sie dem Beitrag den Kommentar zu, indem Sie PUTdem Assoziations-URI ein a ausgeben .

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

Beachten Sie, dass Sie im letzten Schritt gemäß der Spezifikation von text/uri-listmehrere URIs senden können, die durch einen Zeilenumbruch getrennte Kommentare identifizieren, um mehrere Kommentare gleichzeitig zuzuweisen.

Noch ein paar Anmerkungen zu den allgemeinen Entwurfsentscheidungen. Ein Post / Kommentar-Beispiel ist normalerweise ein großartiges Beispiel für ein Aggregat, was bedeutet, dass ich den Rückverweis von der Commentauf die Postund auch die CommentRepositoryvollständige vermeiden würde . Wenn die Kommentare keinen eigenen Lebenszyklus haben (was normalerweise nicht in einer Beziehung im Kompositionsstil der Fall ist), werden die Kommentare eher direkt inline gerendert, und der gesamte Prozess des Hinzufügens und Entfernens von Kommentaren kann eher mithilfe von behandelt werden JSON-Patch . Spring Data REST hinzugefügt Unterstützung für die in der aktuellen Release Candidate für die kommende Version 2.2.

Oliver Drotbohm
quelle
4
Interessiert sich hier von den Downwählern, was der Grund für die Abstimmungen war;).
Oliver Drotbohm
3
Ich bin mir nicht sicher, was die Wähler angeht ... Ich habe nicht einmal den Ruf, das zu tun! Der Grund, warum ich Kommentare nicht unbedingt gerne mit Posts in Einklang bringe, ist, dass ich das (unwahrscheinliche) Szenario in Betracht ziehe, wenn ich Tausende von Kommentaren für einen einzelnen Post habe. Ich möchte in der Lage sein, die Sammlung von Kommentaren zu paginieren, anstatt jedes Mal, wenn ich auf den Inhalt des Beitrags zugreifen möchte, die gesamte Sammlung von Kommentaren abzurufen.
Ccampo
25
Die intuitivste Möglichkeit für mich, einen Kommentar zu veröffentlichen, besteht darin, einen POST an localhost zu senden: 8080 / posts / 1 / Kommentare . Ist es nicht der einfachste und sinnvollste Weg, dies zu tun? Gleichzeitig sollten Sie weiterhin über ein dediziertes Kommentar-Repository verfügen können. Ist es der Feder- oder HAL-Standard, der dies nicht zulässt?
Aycanadal
4
@OliverGierke Ist dies immer noch die empfohlene / einzige Möglichkeit, dies zu tun? Was ist, wenn das Kind nicht nullbar ist ( @JoinColumn(nullable=false))? Es wäre nicht möglich, zuerst das untergeordnete Element und dann die übergeordnete Zuordnung zu setzen / zu patchen.
JW Lim
2
Gibt es eine Anleitung zur Verwendung von APIs, die mit Spring Data Rest erstellt wurden? Ich habe es 2 Stunden lang gegoogelt und nichts gefunden. Danke dir!
Skeeve
2

Es gibt zwei Arten der Zuordnung von Zuordnung und Zusammensetzung. Im Falle einer Assoziation haben wir das Join-Tabellen-Konzept wie verwendet

Mitarbeiter - 1 bis n-> Abteilung

So werden 3 Tabellen für den Fall Association Employee, Department, Employee_Department erstellt

Sie müssen nur das EmployeeRepository in Ihrem Code erstellen. Abgesehen davon sollte das Mapping so sein:

class EmployeeEntity{

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

   }

}

Die Abteilungsentität enthält keine Zuordnung für den Ausgabeschlüssel. Wenn Sie also jetzt die POST-Anforderung zum Hinzufügen eines Mitarbeiters mit Abteilung in einer einzelnen JSON-Anforderung versuchen, wird sie hinzugefügt.

Naveen Goyal
quelle
1

Ich hatte das gleiche Szenario und musste die Repository-Klasse für die Unterentität entfernen, da ich eine bis viele Zuordnungen verwendet und Daten durch die Hauptentität selbst gezogen habe. Jetzt bekomme ich die gesamte Antwort mit Daten.

Selva
quelle
1
Diese Sache, über die Sie sprechen, kann leicht mit Projektionen gemacht werden
kboom
0

Erstellen Sie für die oneToMany-Zuordnung einfach ein POJO für die Klasse, die Sie zuordnen möchten, und eine @ OneToMany-Annotation, und intern wird es dieser Tabellen-ID zugeordnet.

Außerdem müssen Sie die serialisierbare Schnittstelle für die Klasse implementieren, in der Sie die Daten abrufen.

Sonnige Chaurasia
quelle