JPA слияние не удается из-за дублирования ключа - PullRequest
1 голос
/ 06 мая 2010

У меня есть простая сущность, Код, которую мне нужно сохранить в базе данных MySQL.

public class Code implements Serializable {

    @Id
    private String key;
    private String description;

    ...getters and setters...
}

Пользователь предоставляет файл, полный ключей, пар описаний, которые я читаю, преобразую в объекты Code и затем вставляю в одну транзакцию, используя em.merge (код). Файл обычно содержит дубликаты записей, с которыми я сталкиваюсь, сначала добавляя их в карту, введенную в поле ключа, когда я их читаю.

Однако возникает проблема, когда ключи отличаются только регистром (например: XYZ и XyZ). Моя карта, конечно, будет содержать обе записи, но во время процесса слияния MySQL видит, что два ключа одинаковы, и вызов слияния не выполняется с MySQLIntegrityConstraintViolationException.

Я мог бы легко это исправить, заглавными буквами, когда я их читал, но я бы хотел точно понять, что происходит не так. Я пришел к выводу, что JPA рассматривает XYZ и XyZ как разные ключи, но MySQL считает, что они одинаковы. Таким образом, когда JPA проверяет свой список известных ключей (или делает все, что делает, чтобы определить, нужно ли ему выполнить вставку или обновление), он не может найти предыдущую вставку и выдать другую, которая затем дает сбой. Это Corrent? Есть ли что-то еще, кроме лучшей фильтрации данных клиента?

Я не определил .equals или .hashCode в классе Code, так что, возможно, это проблема.

Ответы [ 2 ]

2 голосов
/ 06 мая 2010

Я не определил .equals или .hashCode в классе Code, так что, возможно, это проблема.

Ну, вы действительно должны, вы не хотите наследовать от поведения Object для сущностей. Если вы хотите использовать первичный ключ, выполнить сравнение с учетом регистра или использовать деловую идентичность - это другая история, но вы, конечно, не хотите использовать ссылочное равенство. Вам не нужны следующие объекты:

Code code1 = new Code();
code1.setKey("abc");

Code code2 = new Code();
code2.setKey("abc");

Для JPA считается другим.

Во-вторых, если вы хотите иметь возможность вставлять сущность с XYZ в качестве ключа и другую с XyZ, то вам следует использовать тип столбца с учетом регистра (вы можете сделать столбец varchar чувствительным к регистру с используя атрибут binary), иначе вы получите нарушение ограничения первичного ключа.

Итак, подведем итог:

  • реализует equalshashCode), решите, нужно ли вам сравнение с учетом регистра key или нет.
  • использовать соответствующий тип столбца на уровне базы данных.
1 голос
/ 06 мая 2010

Это зависит от того, как ваш столбец определен в mySQL. MySQL является странным из баз данных в этом VARCHAR и аналогичных столбцах по умолчанию для совпадений без учета регистра. Если вы хотите, чтобы XYZ и XyZ представляли собой разные допустимые параметры, вам нужно изменить оператор CREATE TABLE, чтобы создать столбец с учетом регистра (см. Документацию для вашей версии mySQL.)

Вероятно, что-то вроде этого:

CREATE TABLE code (
  key VARCHAR(32) BINARY,
  value VARCHAR(32) BINARY
)
...