Изменить сущность @OneToMany в Spring Data Rest без ее хранилища.
В моем проекте я использую объект типа A, который имеет отношение OneToMany (orphanRemoval = true, cascade = CascadeType.ALL, fetch = FetchType.EAGER) к объектам типа B. Мне нужен SpringDataRest (SDR) для хранения полного полного объекта A с его объектами B (потомками) с использованием одного запроса POST. Я попробовал несколько комбинаций в SDR, единственное, что сработало для меня, было создать @RepositoryRestResource для объекта A и создать @RepositoryRestResource также для объекта B, но пометить this (B) как exported=false (если я не создавал репозиторий вне объекта B это вообще не будет работать -> просто объект будет храниться в одном запросе POST, но не его дочерние элементы (отношение @OneToMany) типа B; тот же результат происходит, если exported = false опущен для репозитория B). Это нормально и единственный способ, как этого добиться (один запрос POST с сохранением всех объектов одновременно)?
Причина, по которой я спрашиваю, в моем предыдущем примере, я должен (я хотел бы) контролировать все объекты "жизненного цикла" с помощью репозитория А. Я согласен с этим, потому что отношение A -> B является композицией (B не существует вне A). Но у меня есть серьезная проблема редактирования (а также удаления) одного определенного объекта типа B с помощью SDR с использованием его родительского репозитория (поскольку объект B не имеет своего собственного экспортированного репозитория). Может быть, это невозможно по определению. Я пробовал эти решения:
- PATCH для "/A/1/B/2" не работает -> метод не разрешен (в заголовках "Allow: GET, DELETE") -> так, также PUT не может быть и речи
- Json Patch также не будет работать - PATCH для "/A/1" с использованием типа содержимого json patch [{"op": "add", "path": "/B/2", ....}] -> "нет такого индекса в целевом массиве" - потому что Json Patch использует скаляр "2" после "массива" в качестве индекса для своего массива. Это не практично в мире Java, когда отношения хранятся в наборе объектов - индексация вообще не имеет смысла.
- Я мог бы экспортировать хранилище (exported=true) объекта B для манипулирования им "напрямую", но таким образом я бы потерял способность хранить весь объект A вместе с его объектами B в одном запросе POST, как я упоминал ранее.
Я хотел бы избежать отправки всего объекта A с одной крошечной модификацией его объекта B для PUT, если это возможно. Спасибо.
1 ответ
Мне удалось изменить дочернюю сущность следующим образом. В качестве примера я использовал следующие объекты:
@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;
}
У меня просто есть хранилище для One
подвергаются.
(Мои примеры используют превосходный HTTP-клиент CLI HTTP)
Удаление элемента с помощью json patch
Этот пример удалит второй элемент в списке manies. Вы можете использовать @OrderColumn, чтобы убедиться, что вы можете положиться на порядок элементов списка.
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"
}
]
Замена всего списка с помощью json patch
Этот образец заменяет список массивом, указанным в значении.
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"
}
]
}
]
Добавление элемента в список с помощью json patch
Этот образец добавляет элемент в конец списка. Также здесь клиенту просто нужно знать длину списка перед обновлением. Так что порядок здесь не имеет значения.
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"
}
}
]
Надеюсь это поможет.