Обработка отношений в запросах POST с помощью Spring Data JPA - PullRequest
0 голосов
/ 26 сентября 2018

У меня есть следующие объекты, и CrudRepository для каждого:

@Entity
class Movie {
    @Id Long id;
    @Column String name;
    @ManyToOne Person director;
}

@Entity
class Person {
    @Id Long id;
    @Column String name;
}

Мой контроллер выглядит так:

@RestController
@RequestMapping("/movies")
class MovieController {

    private MovieRepository movies = ...;
    private PersonRepository people = ...;

    @PostMapping
    public Movie create(@RequestBody MovieRequest request) {
        // Get the director
        Person director = people.findById(request.directorId);

        // Create the new movie
        Movie movie = new Movie();
        movie.name = request.name;
        movie.director = director;

       // Save the new movie
       return movies.save(movie);
    }
}

class MovieRequest {
    String name;
    Long directorId
}

Как видите, createМетод сначала загружает режиссера по его идентификатору, затем создает новый фильм и, наконец, сохраняет его.Это вызывает две поездки в базу данных: первый, чтобы получить режиссера, и второй, чтобы сохранить фильм.

В этом случае это не большая проблема, но может быть сущность с большим количеством отношений,это означает, что потенциально можно выполнить множество запросов для выполнения одной вставки.

Вопрос : Я хотел бы сохранить новый фильм в отдельной операции базы данных.Есть ли способ избежать первоначального запроса от человека?Есть ли лучший способ обработки таких случаев?

Ответы [ 3 ]

0 голосов
/ 26 сентября 2018

Это будет ужасно, но у вас есть personId в вашем запросе, поэтому вы можете отобразить свой фильм с длинным personId

class Movie {
    @Id Long id;
    @Column String name;
    @ManyToOne Person director;

    @Column(name="PERSON_ID")
    long personId;
}

в вашем контроллере

movie.setPersonId(request.directorId);
0 голосов
/ 29 сентября 2018

Я не думаю, что ваша таблица MOVIE содержит столбец 'DIRECTOR_NAME' (при условии, что вы следуете 2-му правилу нормализации).Это должно быть only DIRECTOR_ID.

Таким образом, вы можете полностью пропустить загрузку имени директора в вашем сценарии (при условии, что directId отправляется с параметрами запроса запроса).

Поскольку у вас есть (должен быть) внешний ключ , ограничивающий между Movie.DIRECTOR_ID и DIRECTOR.ID, он будет следить за любым нарушением ограничения, если вы пытаетесь вставить любой DIRECTOR_ID, которыйне существуетТак что вам не нужно беспокоиться.

0 голосов
/ 26 сентября 2018

Невозможно сказать, какой код Person относится к вашему новому Movie.Поэтому вам действительно нужно выполнить запрос и вручную установить связь.

Существует альтернатива, которая была бы возможна только в том случае, если ваша конечная точка создаст Person в то же время, когда она создаст Movie.Затем вы можете просто выполнить 2 действия сохранения или использовать CascadeType=ALL для выполнения одного действия сохранения.


Если вы можете изменить параметры запроса, может быть хорошим выбором для получениязавершить Person объект, вместо того, чтобы принять directorId.Таким образом, вы можете просто сделать ассоциацию movie.director = director;.

Будьте осторожны с этим видом подхода: если полученный объект Person не сохранен в вашей базе данных, вы получите исключение.


Может быть, вы могли бы создать кеш для Directors.Например, если все ваши директора сохранены в Redis, вы можете выполнить поиск Director, соответствующий полученному directorId, и затем выполнить сопоставление.

Конечно, вам все равно потребуется выполнить вторую операцию., но это может быть намного дешевле, чем запросить базу данных.

...