Как предотвратить дополнительный запрос для отношения OneToOne - PullRequest
0 голосов
/ 26 мая 2020

У меня есть таблицы:

users (id, name, email, password)
user_statuses (user_id, is_premium, is_advanced, user_rank_id)
user_ranks (id, name, ordinal)

Таким образом, отношение между User и UserStatus равно 1-1, и у меня есть следующие классы сущностей:

@Entity
@Table(name = "users")
@Getter
@Setter
@NoArgsConstructor
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    private String name;
    private String email;
    private String password;

    @OneToOne(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private UserStatus status;
}

@Entity
@Table(name = "user_statuses")
@Getter
@Setter
@NoArgsConstructor
public class UserStatus {
    @Id
    private long id;

    @MapsId
    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;

    private boolean isPremium;
    private boolean isAdvanced;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_rank_id")
    private UserRank rank;
}

@Entity
@Table(name = "user_ranks")
@Getter
@Setter
@NoArgsConstructor
public class UserRank {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    private String name;
    private int ordinal;
}

Затем я создал конечную точку "/ users / {id} ", который должен возвращать адрес электронной почты пользователя в виде строки:

@GetMapping("/users/{id}")
public String getUserEmail(@PathVariable("id") long userId) {
    User user = service.getUser(userId);
    return user.getEmail();
}

Когда я вызываю указанную выше конечную точку, я получаю адрес электронной почты пользователя в качестве ответа, однако, глядя в журнал консоли, я вижу, что спящий режим выполнен 2 запроса, но никто не просил его сделать это:

Первый для получения информации о пользователе:

SELECT
    user0_.id AS id1_2_0_,
    user0_.email AS email2_2_0_,
    user0_.name AS name3_2_0_,
    user0_.password AS password4_2_0_
FROM
    users user0_
WHERE
    user0_.id = 1;

И второй для получения статуса пользователя, связанного с этим объектом «Пользователь»:

SELECT
    userstatus0_.user_id AS user_id1_1_0_,
    userstatus0_.is_advanced AS is_advan2_1_0_,
    userstatus0_.is_premium AS is_premi3_1_0_,
    userstatus0_.user_rank_id AS user_ran4_1_0_
FROM
    user_statuses userstatus0_
WHERE
    userstatus0_.user_id = 1;

Итак, я смущен: почему спящий режим запускает второй запрос, когда я устанавливаю fetch = FetchType.LAZY для каждого отношения ... Похоже, что LAZY игнорируется для аннотации @OneToOne?

Я делаю не использовать EntityGraph.

Как остановить спящий режим для выполнения второго запроса?

EDIT

Итак, оказывается, что Hibernate игнорирует мою ленивую подсказку, потому что это необходимо решить, следует ли инициализировать свойство с помощью N ULL или ProxyObject, что имеет смысл. Эта ссылка хорошо объясняет это:

https://thorben-janssen.com/hibernate-tip-lazy-loading-one-to-one/

Однако эта ссылка также предполагает, что лучший способ смоделировать это - однонаправленный One to One, и он говорит, что я могу всегда получать UserStatus на основе идентификатора пользователя (поскольку обе таблицы "имеют общий" первичный ключ)

Однако это меня немного смущает, потому что я могу получить обе строки с помощью одного запроса (SELECT * FROM users LEFT JOIN user_statuses ON users.id = user_statuses.user_id), но с описанным подходом в ссылке мне нужно 2 запроса, и, насколько я знаю (что я могу ошибаться), 1 запрос лучше, чем выполнение 2 запросов, а также, если я хочу получить 25 пользователей и их статусы пользователей, мне также понадобятся 2 запросы, один для выборки пользователей, а затем для выборки основных состояний пользователей и, наконец, записи вложенных для каждого цикла, чтобы присоединиться к этим объектам. Я мог бы просто выполнить один-единственный запрос, чтобы получить все ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...