Используя saveOrUpdate () в В спящем режиме, создает новые записи вместо того, чтобы обновить существующие

У меня есть класс Пользователь

class User { 
  int id;
  String name;
}

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

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

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

Например, в моем DB я ссорюсь INSERT INTO User VALUES ('Bill');

Main.java

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

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

16
задан user443854 20 February 2013 в 20:47
поделиться

5 ответов

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

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

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

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

Когда вы делаете:

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

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

30
ответ дан 30 November 2019 в 16:00
поделиться

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

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

Почему haven «Разве вы просто не наложили уникальное ограничение на« Имя »в базе данных и не создали ограничение первичного ключа для идентификатора?

1
ответ дан 30 November 2019 в 16:00
поделиться

То есть вы хотите, чтобы:

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

заметил, что u1 и u2 - один и тот же счет, и сохранил его только один раз? У Hibernate нет способа узнать, что Биллы - это один и тот же человек. Он только смотрит на id пользователя 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, и уникальность на имени. Поэтому вам нужен какой-то вариант merge, который это делает. Очень приблизительно, вам нужно что-то вроде этого:

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;
}
17
ответ дан 30 November 2019 в 16:00
поделиться

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

Для обновления вам необходимо иметь идентификатор, связанный с пользовательским объектом. Установка только атрибута name не поможет. Если вы хотите обновить независимо от того, не имея идентификатора, используйте 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();
1
ответ дан 30 November 2019 в 16:00
поделиться

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

-1
ответ дан 30 November 2019 в 16:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: