In my project I use object of type A which has OneToMany relation (orphanRemoval = true, cascade = CascadeType.ALL, fetch = FetchType.EAGER) to objects of type B. I need SpringDataRest (SDR) to store complete full A object with its B objects (children) using single one POST request. I tried several combinations in SDR, the only one which worked for me, was to create @RepositoryRestResource for object A and to create @RepositoryRestResource also for object B, but mark this (B) as exported=false (if I did not create repository out of object B at all, it would not work -> just A object would be stored on single POST request, but not its children (@OneToMany relation) of type B; the same outcome occurs if exported=false is omitted for B repository). Is this ok and the only way how to achieve it (single POST request with storing all objects at once)?
The reason I'm asking, in my previous example, I have to (I would like to) control all objects "lifecycle" by using A's repository. I am ok with it, because A->B relation is composition (B does not exists outside of A). But I have serious problem of editing (also removing) one certain object of type B by SDR using its parent repository (since object B doest not have its own repository exported). Maybe, this is not possible by definition. I have tried these solutions:
- PATCH for "/A/1/B/2" does not work -> method not allowed (in headers is "Allow: GET, DELETE") -> so, also PUT is out of question
- Json Patch would not work either - PATCH for "/A/1" using json patch content-type [{"op": "add", "path": "/B/2", ....}] -> "no such index in target array" - because Json Patch uses scalar "2" after "array" as a index to its array. This is not practical in Java world, when relations are kept in Set of objects - indexing has no meaning at all.
- I could export repository (exported=true) of object B for manipulating it "directly", but this way I would loose ability to store the whole object A with its B objects at one single POST request as I have mentioned before.
I would like to avoid sending the whole A object with one single tiny modification of its B object for PUT, if possible. Thank you.
I managed to change the child entity as follows. As a sample I used the following entities:
@Entity
@Data
@NoArgsConstructor
public class One {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToMany(cascade = ALL)
private List<Many> manies = new ArrayList<>();
}
@Entity
@Data
@NoArgsConstructor
public class Many {
public Many(String name) {
this.name = name;
}
@Id
@GeneratedValue
private Long id;
private String name;
}
I just have a repository for One
exposed.
(My examples use the excellent httpie - CLI HTTP client)
Removing an item using json patch
This example will remove the second item in the manies list. You could use @OrderColumn to make sure that you can rely on the order of list items.
echo '[{"op":"remove", "path":"/manies/1"}]' | http PATCH :8080/ones/1 Content-Type:application/json-patch+json -v
PATCH /ones/1 HTTP/1.1
Content-Type: application/json-patch+json
[
{
"op": "remove",
"path": "/manies/1"
}
]
Replacing the entire list using json patch
This sample replaces the list with the array specified in the value.
echo '[{"op":"add", "path":"/manies", "value":[{"name":"3"}]}]' | http PATCH :8080/ones/1 Content-Type:application/json-patch+json -v
PATCH /ones/1 HTTP/1.1
Accept: application/json
Content-Type: application/json-patch+json
[
{
"op": "add",
"path": "/manies",
"value": [
{
"name": "3"
}
]
}
]
Adding an item to the list using json patch
This sample adds an item to the end of a list. Also here the client just needs to know the length of the list before the update. So the order does not really matter here.
echo '[{"op":"add", "path":"/manies/-", "value":{"name":"4"}}]' | http PATCH :8080/ones/1 Content-Type:application/json-patch+json -v
PATCH /ones/1 HTTP/1.1
Accept: application/json
Content-Type: application/json-patch+json
[
{
"op": "add",
"path": "/manies/-",
"value": {
"name": "4"
}
}
]
Hope this helps.
来源:https://stackoverflow.com/questions/34843297/modify-onetomany-entity-in-spring-data-rest-without-its-repository