Изменить сущность @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"
        }
    }
]

Надеюсь это поможет.

Другие вопросы по тегам