Правильный способ проверки на нарушение ограничений внешнего ключа в режиме гибернации?

#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, но в этом случае вы все равно не установили бы никаких идентификаторов.