Использование saveOrUpdate() в Hibernate создает новые записи вместо обновления существующих

У меня есть класс User

class User { 
  int id;
  String name;
}

где id - собственный генератор в User.hbm.xml, а name - первичный ключ в БД.

В моей базе данных я сохранил некоторую информацию о Пользователях.

Чем я хочу подключиться к этой информации о пользователе.

Например, в моей БД есть строка INSERT INTO User VALUES ('Bill');

Main.java

User bill = new User();
bill.setName("Bill");
session.saveOrUpdate(bill);

Этот код всегда пытается вставить новую строку Bill в таблицу, а не обновлять существующую строку Bill.

Ответы

Ответ 1

Этот код всегда пытается вставить законопроект в базу данных, а не обновлять, когда строка о Билле существует в БД...

Из раздела 10.7. Автоматическое определение состояния документации ядра Hibernate:

saveOrUpdate() выполняет следующие действия:

  • если объект уже является постоянным в этой сессии ничего не делать
  • если другой объект, связанный с сессия имеет тот же идентификатор, throw исключение
  • , если объект не имеет идентификатор, save() it
  • если идентификатор объекта имеет значение присваивается вновь созданной объект, save() it
  • если объект с версией <version> или <timestamp>, а версия значение свойства - такое же значение присваивается вновь созданной объект, save() it
  • в противном случае update() объект

Когда вы выполните:

User bill = new User();
bill.setName("Bill");
session.saveOrUpdate(bill);

Этот вновь созданный экземпляр не имеет назначенного значения идентификатора и saveOrUpdate() будет save() он, как задокументировано. Если это не то, что вы хотите, сделайте name основным ключом.

Ответ 2

Итак, вы хотите:

User u1 = new User("Bill");
session.save(u1);
User u2 = new User("Bill");
session.saveOrUpdate(u2);

заметить, что u1 и u2 - это один и тот же Билл и только один раз его хранить? Hibernate не имеет никакого способа узнать, что счета - это один и тот же человек. Он смотрит только на идентификатор пользователя u2, видит, что он не установлен, заключает, что u2 следует вставлять, пытается и сообщает об исключении.

SaveOrUpdate сохраняет как полностью новый объект, так и загруженный объект, который в настоящее время подключен к сеансу. Так что это работает (если у вас есть метод findByName где-то и есть другой атрибут, скажем, favoriteColor):

User u1 = new User("Bill");
u1.setFavoriteColor("blue");
session.saveOrUpdate(u1);
User u2 = findByName("Joe");
u2.setFavoriteColor("red");
session.saveOrUpdate(u2);

Но это не то, что вы хотите, правильно?

Ваша проблема усугубляется вашей сущностью, имеющей суррогатный первичный ключ и, отдельно, бизнес-ключ (принудительный с помощью ограничения уникальности). Если у вас не было поля id и только имя как первичный ключ, вы можете использовать merge() (для обсуждения saveOrUpdate vs merge, смотрите здесь):

User u1 = new User("Bill");
u1.setFavoriteColor("blue");
session.save(u1);
User u2 = new User("Bill");
u2.setFavoriteColor("red");
u2 = session.merge(u2);

Но у вас этого нет, вам нужно обеспечить ограничение PK на id и уникальность имени. Таким образом, вам понадобится некоторое изменение слияния, которое это делает. Очень грубо, вам нужно что-то в этом роде:

public User mergeByName(User user) {
    User merged;
    User candidate = findByName(user.getName());
    if (candidate != null) {
        user.setId(candidate.getId());
        merged = session.merge(user);
    } else {
        session.save(user);
        merged = user;
    }
    return merged;
}

Ответ 3

Итак, Id не сохраняется в базе данных?

Почему Id не является первичным ключом в БД, если вы сопоставляете его в Hibernate как идентификатор?

Почему вы не указали уникальное ограничение на "Имя" в базе данных и не создали ограничение первичного ключа на Id?

Ответ 4

Первый вопрос: если вам нужно получить пользователя с именем "Билл". Как бы Вы это сделали? Это должно дать вам представление.

Для обновления необходимо иметь идентификатор, связанный с объектом пользователя. Наличие набора атрибутов имени не поможет. Если вы хотите обновить независимо, не имея идентификатора, используйте HQL в качестве запроса.

Query query = session.createQuery("update User u set u.name = :newName where u.name=:name");
query.setString("name", "Bill");
query.setString("newName", "John");
query.executeUpdate();

Ответ 5

Вы должны использовать session.update(объект) во время обновления, и session.save(объект) при сохранении

Ответ 6

Если поле имени является первичным ключом. Затем, если вы устанавливаете одно и то же имя более одного раза, как он будет создавать новую запись. Возможно, вы не понимаете концепцию правильно.