Я искал информацию о том, как реализовать следующую связь в спящем режиме, и, хотя руководство по спящему режиму очень подробное, я не нашел следующий адрес использования.
У меня есть требование иметь связь между сущностями, где связь имеет несколько атрибутов, помимо внешних ключей для связанных сущностей. Спецификации для отношения:
- Контейнер связан с Содержанием через Положение.
- Позиция не может существовать без Контейнера и Содержимого предмета.
- Следовательно, если удаляется либо Контейнер, либо Содержащийся элемент, Позиция должна быть удалена.
- Контейнер может содержать 0 или более позиций.
- Позиция относится к одному и только одному Содержащемуся предмету.
Мне удалось настроить большинство требований с помощью аннотаций, и это работает довольно хорошо, за исключением каскадного удаления из элемента Contained. У меня есть обходной путь для выполнения этого, описанный ниже, но я хотел бы настроить это действие с помощью аннотаций, чтобы база данных автоматически выполняла эту работу, чтобы иметь более надежную ссылочную целостность.
Это отображение, которое у меня пока есть:
@Entity
public class Container
{
@OneToMany(cascade = CascadeType.ALL,
orphanRemoval = true,
fetch = FetchType.EAGER)
@JoinColumn(name = "container_fk")
public Set<Position> getPositions() { return this.positions; }
public void setPositions(final Set<Position> positions) { this.positions = positions; }
private Set<Position> positions;
...
}
@Entity
public class Position
{
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "container_fk", insertable = false, updatable = false)
@OnDelete(action = OnDeleteAction.CASCADE)
public Container getContainer() { return this.container; }
public void setContainer(Container container) { this.container = container; }
private Container container;
@NaturalId
@OneToOne(optional = false, fetch = FetchType.EAGER)
@JoinColumn(name = "contained_fk")
public Contained getContained() { return this.contained; }
public void setContained(Contained contained) { this.contained = contained; }
private Contained contained;
// other attributes are owned by this relationship
// (i.e., they don't make sense in either Container or Contained.
...
}
Чтобы удалить Позицию, при удалении элемента Contained в коде ContainedDao реализовано следующее (представлено без обработки исключений, а управление сеансом выполняется в базовом классе Dao для простоты):
@Repository
@Transactional(rollbackFor = Throwable.class)
public class ContainedDao extends TransactionalDao<Contained>
{
public void delete(String id)
{
final Session session = getSession();
// If there is a Position associated to the Contained item delete it,
// and remove it from any Container collection.
Position position = (Position) session.createCriteria(Position.class)
.createCriteria("contained")
.add(Restrictions.eq("id", id))
.uniqueResult();
if (position != null)
{
position.getContainer().getPositions().remove(position);
session.delete(position);
}
// Delete the Contained item.
Contained object = session.load(Contained.class, id);
session.delete(contained);
}
}
Я хотел бы как-то настроить аннотации так, чтобы метод ContainedDao.delete был упрощен до простого:
// Delete the Contained item.
Contained object = session.load(Contained.class, id);
session.delete(contained);
Возможно ли это? Или мое текущее решение - лучшее, что я могу получить? Есть ли лучший способ приблизиться к этому? Обратите внимание, что ключевым фактором здесь является то, что Position содержит дополнительные атрибуты; в противном случае, я бы настроил связь между Контейнером / Содержимым напрямую и позволил бы hibernate управлять ассоциацией.