#java #spring-boot #hibernate #jpa #spring-data-jpa
#java #весенняя загрузка #режим гибернации #jpa #spring-data-jpa
Вопрос:
У меня есть две таблицы, которые уже существуют внутри postgres, давайте назовем таблицу A и таблицу B. Один столбец таблицы B имеет ограничение внешнего ключа в том смысле, что он должен быть первичным ключом таблицы A. Таким образом, между B и A существует отношение «многие к одному», где несколько записей в таблице B соответствуют одной записи таблицы A.
Сущность для обеих этих таблиц определяется следующим образом.
public class TableA implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private Long userId;
@Column(name = "name")
private String name;
@Column(name = "email")
private String email;
@Column(name = "phone_number")
private String phoneNumber;
}
Сущность TableB определяется следующим образом:
public class Shots implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "item_id")
private Long itemId;
@Column(name = "user_id")
private Long userId;
}
Где userId — это сопоставление внешнего ключа с первичным ключом user_id в таблице A.
Эти ограничения уже определены в базовой базе данных postgres, поэтому я не рассматривал возможность использования отношения аннотаций @ManyToOne (все еще пытаюсь разобраться с этим).
В настоящее время я обрабатываю случай, когда происходит нарушение ограничений внешнего ключа, следующим образом:
try {
tableBrepository.save(newShot);
} catch (ConstraintViolationException ex) {
logger.error("Violating foreign key constraint" ex.getMessage());
}
Мой вопрос в том, есть ли лучший способ проверить это нарушение? Могу ли я что-нибудь сделать, чтобы в целом лучше структурировать ограничение внешнего ключа в Spring Data JPA?
Комментарии:
1. Вы можете сопоставить, используя @OneToMany и fetch before, чтобы проверить наличие или выдать исключение vladmihalcea.com /…
2. Единственный другой способ без использования сопоставления — проверить с помощью дополнительного запроса, находится ли объект в БД или нет. Теперь для проверки потребуется дополнительный запрос, но я думаю, что когда вы имеете дело с идентификаторами, вы не можете доверять клиенту и всегда должны проверять в любом случае. Проблема с вашим подходом заключается в том, что у вас есть несколько таких полей и вы хотите вернуть конкретную ошибку. И даже при сопоставлении вам потребуется извлечь объект, поэтому дополнительный запрос.
Ответ №1:
Таким образом, между B и A существует отношение «многие к одному», где несколько записей в таблице B соответствуют одной записи таблицы A.
Такого рода вещи в объектах JPA обрабатываются с @ManyToOne
помощью аннотаций. Обычно вы не ссылаетесь на какое-либо поле id напрямую, а сообщаете JPA, что там должно быть. Итак, в вашем классе TableB (или я должен его назвать… Выстрелы?) должно быть что-то вроде:
@ManyToOne
private TableA tableA;
// and get rid of this
// @Column(name = "user_id")
// private Long userId;
И необязательно — так что не обязательно — вы могли бы иметь в своей таблице:
@OneToMany
private List<TableB> tableBsOrShouldICallYouShots;
Я не уверен, в чем ваша реальная проблема, но при настройке и обращении к полям идентификатора напрямую могут возникнуть ваши трудности.
Теперь, если вы, например, используете репозиторий, чтобы найти что-то TableB
, что вы можете после этого просто сделать
tableB.getTableA()
И при сохранении вы бы перед этим сделали:
tableB.setTableA(somSortOftableA);
// so not tableB.setUserId(someLongIdFOrtableA);
Теперь дело в том, что нет проблем со ссылочной целостностью, потому что вам не нужно знать никаких идентификаторов, и вы не можете установить какой-либо неправильный идентификатор. Если вам сначала не нужно получить TableA по идентификатору, прежде чем устанавливать его в TableB, но в этом случае вы все равно не установили бы никаких идентификаторов.