Итак, вы хотите:
User u1 = new User("Bill");
session.save(u1);
User u2 = new User("Bill");
session.saveOrUpdate(u2);
чтобы заметить, что u1 и u2 - это один и тот же Билл, и хранить его только один раз? Hibernate не может знать, что счета являются одним и тем же человеком. Он только смотрит на идентификатор пользователя u2, видит, что он не установлен, приходит к выводу, что u2 должен быть вставлен, пробует это и сообщает об исключении.
SaveOrUpdate сохраняет как совершенно новый объект, так и загруженный объект, который в данный момент присоединен к сеансу. Так что это работает (при условии, что у вас есть метод findByName где-то и есть другой атрибут, скажем, favouriteColor):
User u1 = new User("Bill");
u1.setFavoriteColor("blue");
session.saveOrUpdate(u1);
User u2 = findByName("Joe");
u2.setFavoriteColor("red");
session.saveOrUpdate(u2);
Но это не то, что вы хотите, верно?
Ваша проблема усугубляется тем, что ваша сущность имеет суррогатный первичный ключ и, отдельно, бизнес-ключ (применяется через ограничение уникальности). Если у вас нет поля id и только имя в качестве первичного ключа, вы можете использовать merge () (для обсуждения saveOrUpdate против слияния, посмотрите здесь ):
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;
}