Измените @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, но пометить это (B) как exported = false (если я не создал репозиторий вне объекта B, это не сработает → просто объект будет храниться в одном запросе POST, но не его дочерних (отношение @OneToMany) типа B, тот же результат возникает, если exported = false опущен для B-репозитория).  Это нормально и единственный способ его достижения (один запрос POST с одновременным хранением всех объектов)?

Причина, по которой я прошу в моем предыдущем примере, я должен (я бы хотел) управлять всеми объектами "жизненный цикл" с помощью репозитория. Я в порядке, потому что отношение A- > B является композицией (B не существует вне A). Но у меня есть серьезная проблема редактирования (также удаления) одного определенного объекта типа B с помощью SDR с использованием его родительского репозитория (поскольку объект B не имеет собственного экспортируемого репозитория). Возможно, это невозможно по определению. Я пробовал эти решения:

  • PATCH для "/A/1/B/2" не работает → метод не разрешен (в заголовках "Разрешить: GET, DELETE" ) → так, также PUT не может быть и речи
  • Json Patch не будет работать - PATCH для "/A/1" с помощью json patch content-type [{ "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.

(Мои примеры используют отличный httpie - клиент HTTP CLI)

Удаление элемента с помощью json-патча

В этом примере будет удален второй элемент в списке муай. Вы можете использовать @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"
        }
    }
]

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