Порядок сохранения отношений OneToMany с JPA и гибернацией

#java #hibernate #jpa-2.0

#java #гибернация #jpa-2.0

Вопрос:

У меня есть эти два компонента:

 public class AgentSubscription {

//...
  @OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}, mappedBy = "subscription")
  @Fetch(FetchMode.SUBSELECT)
  @OrderBy("ID_SUBSCRIPTION")
  private List<OutputChannel> channels;
//...
}
  

и

 public class OutputChannel {
//...
  @ManyToOne(fetch = FetchType.EAGER)
  @JoinColumn(name = "ID_SUBSCRIPTION", nullable = false)
  private AgentSubscription subscription;
//...
}
  

Если мы попытаемся использовать этот метод:

   @Transactional
  public void addChannel(AgentSubscription subscription, OutputChannel channel)
  {
    try
    {
      List<OutputChannel> channels = new ArrayList<OutputChannel>();
      channels.add(channel);
      subscription.setChannels(channels);
      subscription = agentSubscriptionDao.insert(subscription);
    }
    catch (Exception e)
    {
      LOGGER.error("Unable to add channel to subscription "   subscription.getSubscriptionId());
    }
  }
  

Мы получаем это исключение:

 javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transient value: com.domain.agent.beans.channel.OutputChannel.subscription
  

Не должен ли гибернация сохранять подписку перед каналом? Может ли это быть проблемой с CascadeType?

Ответ №1:

Прежде всего, вам нужно установить subscription в channel объекте, который ссылается на него, и значение не обнуляется. Это является причиной исключения, которое вы получили. Этот тип сопоставления создает AgentSubscription внешний ключ в OutputChannel таблице, поэтому вам всегда нужно его устанавливать, каскадный или нет. Hibernate не выполняет никакой автоматической настройки или что-то в этом роде. Итак, с точки зрения вашего кода, добавление

 channel.setSubscription(subscription);
  

перед вызовом DAO insert проблема должна быть решена. Таким образом, когда entityManager.persist(subscription) вызывается (или как бы вы ни сохранялись), channel он также будет сохранен.