Использование 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
Если поле имени является первичным ключом. Затем, если вы устанавливаете одно и то же имя более одного раза, как он будет создавать новую запись. Возможно, вы не понимаете концепцию правильно.