Невозможно использовать аннотацию JPA @OneToOne (cascade = CascadeType.ALL) - PullRequest
0 голосов
/ 20 ноября 2018

У меня есть родительский класс Contact, который имеет отношение один к одному с ContactType.

@OneToOne(cascade=CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "type")
private ContactType contactType;

Я пытаюсь создать новый контакт с помощью ContactRepository.save (), который расширяет JPARepository.Я получаю следующую ошибку.

Нарушение типа ограничения PRIMARY KEY.Невозможно вставить повторяющийся ключ в объект ContactType

Если я изменю объявление типа контакта на следующее:

@OneToOne(cascade=CascadeType.MERGE, orphanRemoval = true)
@JoinColumn(name = "type")
private ContactType contactType;

Я получаю следующую ошибку:

объект ссылается на несохраненный временный экземпляр - сохраните временный экземпляр перед сбросом

Код, используемый для создания контакта (он просто вызывает JPARepository.save ()):

contactsRepository.save(contact);

Какиспользуйте объединение и сохраняйте данные одновременно.

Ответы [ 2 ]

0 голосов
/ 20 ноября 2018

Вызов contactsRepository.save(contact) с:

@OneToOne(cascade=CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "type")
private ContactType contactType;

вызывает исключение, потому что контекст постоянства каскадирует операцию persist и видит contactType как transient с установленным первичным ключом, готовым к сохранению.Строка с таким же PK уже существует, поэтому возникает ошибка.

Второй случай:

@OneToOne(cascade=CascadeType.MERGE, orphanRemoval = true)
@JoinColumn(name = "type")
private ContactType contactType;

Операция persist (не merge), следовательно, не каскадная.Постоянный контекст видит contactType как transient и не может идти дальше с persist, поскольку одна из зависимостей находится в состоянии transient.

Решение

Избавьтесь от каскада:

@OneToOne
@JoinColumn(name = "type")
private ContactType contactType;

Перед вызовом contactsRepository.save(contact); убедитесь, что contactType находится в управляемом состоянии.Вы можете сделать это следующим образом:

contact.setContactType( entityManager.getReference(ContactType.class, contactType.getId()));

Убедитесь, что вы заменили getId() на получатель первичного ключа.

Слияние contactType в контекст постоянства с contact.setContactType(contactTypeRepository.merge(contactType)); также допустимо.

0 голосов
/ 20 ноября 2018

Ваши комментарии упоминаются:

Первичный ключ - это строка типа.Я хочу вставить новую строку для ввода, если пользователь вводит новый тип Пример: «Тип2» при создании нового контакта.Если пользователь вводит уже существующий тип, то я не хочу вставлять новую строку.

Тогда имеет смысл, почему вы получаете сообщение Не удается вставить дубликат ключа.

Реальность такова, что между контактом и типом контакта нет однозначного отношения, поскольку для каждого контакта не существует одного типа контакта.Как вы сказали, типы контактов используются повторно.То, что вам следует делать, - это использовать соотношение один к другому между типом контакта и контактом, поскольку один контакт может иметь только один тип контакта, но один тип контакта может применяться к нескольким контактам.Итак, один и тот же тип контакта может быть одним или несколькими контактами.

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

...