Как управлять картой несохраненных сущностей в сеансе 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 в качестве ключа? Мне не кажется разумным, что вы можете искать новых участников по идентификатору, так как они еще не имеют никакой идентичности.

Если поиск новых членов не требуется, я предложу вам:

  1. отдельный атрибут, хранящий "новых членов"
  2. есть метод commit() и revert() в вашей сущности
  3. Пользователь будет вызывать 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();
  }
}

Таким образом, у вас есть представление о "предлагаемых членах", которые вы можете повторять, сохраняя при этом действительные и несохраненные элементы отдельно.

Другие вопросы по тегам