Сохранение нового, но идентичного объекта с дублирующейся записью в отчете JPA.

StackOverflow https://stackoverflow.com/questions/1932258

  •  20-09-2019
  •  | 
  •  

Вопрос

У меня есть проект JPA, подключенный к базе данных MySQL, где мой объект сущности отображается в таблицу с ограничением на два столбца.То есть:

@Entity
@Table(name = "my_entity")
class MyEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id")
    private Integer id;
    @Basic(optional = false)
    @Column(name = "myField1")
    private String myField1;
    @Basic(optional = false)
    @Column(name = "myField2")
    private int myField2;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "myEntity")
    private Set<OtherEntity> otherEntitySet;
}

В базе данных таблица my_entity имеет уникальное ограничение (myField1, myField2).Проблема в том, что если я удалю существующий объект с помощью EntityManager.remove(entity), а затем добавлю новый с помощью EntityManager.persist(entity), база данных выдаст ошибку о дублирующейся строке.

Например:

entityManager.getTransaction().begin();

MyEntity entity1 = new MyEntity();
entity1.setMyField1("Foo");
entity1.setMyField2(500);
entityManager.persist(entity1);

entityManager.getTransaction().commit();
entityManager.getTransaction().begin();

entityManager.remove(entity1);

MyEntity entity2 = new MyEntity();
entity2.setMyField1("Foo");
entity2.setMyField2(500); 
entityManager.persist(entity2);

entityManager.getTransaction().commit();

Это дает мне исключение MySQLIntegrityConstraintViolationException, жалующееся на то, что это повторяющаяся запись.Я предполагаю, что это потому, что он пытается добавить новую запись перед удалением старой.Есть ли способ сохранить этот порядок?Или есть ли способ использовать JPA, чтобы предотвратить эту ситуацию?Это не совсем распространенный вариант использования, но меня беспокоит пользователь, который пытается удалить объект, чтобы избавиться от всех связанных с ним данных и начать все сначала, а затем воссоздает более простые поля, а затем обнаруживает, что данные так и не были удалены.

Реализации hashCode и Equals следующие:

public int hashCode() {
    int hash = 0;
    hash += (getMyField1().hashCode() + getMyField2());
    return hash;
}

public boolean equals(Object object) {
    if (!(object instanceof MyEntity)) {
        return false;
    }
    MyEntity other = (MyEntity) other;
    return (getMyField2() == other.getMyField2()) &&
        (getMyField1().equals(other.getMyField1()));
}
Это было полезно?

Решение

Я не думаю, что существует какой-либо стандартный способ указать порядок операций в JPA, поэтому нет никакой гарантии, в каком порядке будут выполняться инструкции.В идеале реализация JPA должна была бы быть достаточно умной, чтобы обнаружить эту ситуацию и выполнить удаление перед вставкой, но это область, в которой они часто терпят неудачу.Альтернативно, если ваша база данных поддерживает отложенную проверку ограничений (например, Oracle поддерживает, а MySQL нет), база данных будет обрабатывать это, ожидая момента фиксации, чтобы выдать уникальное исключение нарушения ограничения.

Таким образом, одно из решений — просто выполнить дополнительную фиксацию после вызова метода удаления(entity1).Другая возможность — перед созданием объекта 2 сначала проверить, существует ли он в базе данных, и если да, просто использовать его.Оба эти варианта могут быть несколько громоздкими и подходить не для всех рабочих процессов.Возможно, вам захочется покопаться в документации вашей текущей реализации JPA, чтобы узнать, предлагают ли они какие-либо расширения, которые могут помочь.

Другие советы

У меня была та же проблема, связанная с UC и вставками/удалениями, происходящими в неправильном порядке.Мне пришлось создать составной ключ для моей сущности, который соответствовал бы столбцам UC.После этого удаления и вставки происходили в правильном порядке.См. этот пост и комментарий о добавлении @EmbeddedId:

https://forum.hibernate.org/viewtopic.php?p=2382504

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top