Как управлять картой несохраненных сущностей в сеансе Hibernate?
На моей сущности (myGroup : Group
) У меня есть свойство коллекции (members : HashMap<Long, GroupMember>
) и я хочу разрешить пользователю добавлять несколько новых (без ответов) GroupMember
с myGroup.members
карта.
Причина, по которой я использую хэш-карту для свойства коллекции, заключается в том, чтобы гарантировать, что использование коллекции является производительным (т.е. должно быть в состоянии получить
GroupMember
по его идентификатору быстро и многократно во время выполнения бизнес-логики).Причина, по которой я не хочу сохранять их сразу же, заключается в поддержке возврата дополнений. Пользователь должен иметь возможность манипулировать
myGroup.members
сопоставление, добавление и удаление членов до тех пор, пока они не будут выполнены, перед сохранением (сохранение сущностей в сеансе Hibernate и очистка).
Проблема в том, что новый GroupMember
Для Hibernate должен быть присвоен нулевой идентификатор, чтобы определить, что они не сохранены.(*) Поскольку элементы находятся на карте и имеют идентификатор, то есть только один новый элемент может быть добавлен до сохранения или возврата. Добавление второго нового члена с нулевым идентификатором просто переопределяет (ссылку на) первое.
Мой вопрос заключается в том, как лучше всего адаптировать свое решение для кода для поддержки добавления нескольких несохраненных объектов в коллекцию (myGroup.members
) сохраняя при этом преимущество в производительности при использовании hashmap или другой карты / словаря?
Примечание: я уже пробовал взломать, в результате чего идентификатор получен из уникальной комбинации данных в GroupMember
экземпляра, а затем, непосредственно перед сохранением, идентификатор устанавливается на ноль, чтобы Hibernate обнаружил, что его необходимо сохранить, но он не элегантен, и я не нашел способа, чтобы он работал надежно.
* Я не совсем понимаю поведение Hibernate в этом отношении.
Сокращенный код для Group
сущность ниже:
@Entity
@Table (name="GROUP")
public class Group
{
private Map<Long,GroupMember> members = new HashMap<Long,GroupMember>();
@OneToMany(fetch = FetchType.LAZY, mappedBy = "ownerGroup", cascade = { CascadeType.ALL })
@MapKey(name="id")
public Map<Long,GroupMember> getMembers() { return this.members; }
public void setMembers(Map<Long,GroupMember> members) { this.members = members; }
// ...other properties and methods...
}
1 ответ
Я немного запутался в том, что вы собираетесь достичь. Члены, которые не сохраняются, не имеют идентификатора. Какое поведение "поиска" для этих участников вы ожидаете, когда вы используете ID в качестве ключа? Мне не кажется разумным, что вы можете искать новых участников по идентификатору, так как они еще не имеют никакой идентичности.
Если поиск новых членов не требуется, я предложу вам:
- отдельный атрибут, хранящий "новых членов"
- есть метод commit() и revert() в вашей сущности
- Пользователь будет вызывать commit() после завершения обновления, а затем новые сущности будут перемещены на фактическую "сопоставленную" карту / список для фактического сохранения.
Если ТРЕБУЕТСЯ поиск новых членов, и, судя по вашему отрывку, вы способны самостоятельно сгенерировать проверенный уникальный ключ, не считаете ли вы, что у вас нет спящего режима для создания идентификатора? У вас есть возможность в Hibernate решить, генерируется ли идентификатор Hibernate (в качестве суррогатного ключа) и предоставляется вами (своего рода естественный ключ). Я полагаю, что самоидентификационное удостоверение более подходит в вашем случае, поскольку вы, похоже, не рассматриваете удостоверение как суррогатный ключ.
Отредактировано: что касается комментария от ОП о причине невозможности хранить его отдельно, его можно легко решить с помощью этого подхода (и я думаю, что это также имеет больше смысла):
(код pusedo)
class Group {
private List<Member> members; // mapped in hibernate
private List<Member> unsavedMembers; // unmapped
public Map<Long, Member> getProposedMemberMap() {
// returned the combined "view" members and unsavedMembers
}
@PreUpdate // you may consider running it it pre-update too
public void commit() {
members.addAll(unsavedMembers);
unsavedMembers.clear();
}
public void revert() {
unsavedMembers.clear();
}
}
Таким образом, у вас есть представление о "предлагаемых членах", которые вы можете повторять, сохраняя при этом действительные и несохраненные элементы отдельно.