title: javax persistence relationship between parent and child. This last child is in turn parent of other child
body: <p>My situation is: entity parent MainSpeech with child Messages. Messages in turn is parent of entity Attachment.</p>
  
  <p>I try to persist/merge an existing MainSpeech by adding a new Massage which have two new Attachments.
  Persist/merge fails because ID_MESSAGE is null. ID_MESSAGE is the foreing key that join Messages with Attachment.</p>
  
  <pre><code>//Entity MainSpeech
  @OneToMany(fetch=FetchType.LAZY,cascade=CascadeType.ALL,mappedBy="mainSpeech")
  public List&lt;Messages&gt; getMessages() {
      return messages;
  }
  public void setMessages(List&lt;Messages&gt; messages) {
      this.messages = messages;
  }
  
  //Entity Messages
  @ManyToOne(fetch=FetchType.LAZY)
  @JoinColumn(name="ID_MAINSPEECH",nullable=false)
  public MainSpeech getMainSpeech() {
      return mainSpeech;
  }
  public void setMainSpeech(MainSpeech mainSpeech) {
      this.mainSpeech = mainSpeech;
  }
  
  @OneToMany(fetch=FetchType.LAZY,cascade=CascadeType.ALL,mappedBy="messages")
  public List&lt;Attachments&gt; getAttachments() {
      return attachments;
  }
  public void setAttachments(List&lt;Attachments&gt; attachments) {
      this.attachments = attachments;
  }
  
  
  //Entity Attachments    
  @ManyToOne(fetch=FetchType.LAZY)
  @JoinColumn(name="ID_MESSAGE",nullable=false)
  public Messages getMessages() {
      return messages;
  }
  public void setMessages(Messages messages) {
      this.messages = messages;
  }
  </code></pre>
  
  <p>My code:</p>
  
  <pre><code>public String inviaRisposta() {
  
      //conversazione is MainSpeech and it is an instance of MainSpeech
      Messaggi messaggio = new Messaggi(autore,
              EnumStatoMessaggio.INVIATO.getValue(),
              testoMsg,
              userWorkContext.getProfiloMessaggistica(),
              identity.getCredentials().getUsername(),
              conversazione);
      //aggiornamento conversazione e inserimento messaggio
      conversazione.getMessaggi().add(messaggio);
  
      List&lt;Allegati&gt; allegati = new ArrayList&lt;Allegati&gt;();
      try {
          if (StringUtils.isNotBlank(fileNameAllegatoUno)) {
              Allegati allegato = new Allegati();
              allegato.setFile(fileAllegatoUno);
              allegato.setDataUpload(new Date());
              allegato.setNomeFile(fileNameAllegatoUno);
              allegati.add(allegato);
          }
          if (StringUtils.isNotBlank(fileNameAllegatoDue)) {
              Allegati allegato = new Allegati();
              allegato.setFile(fileAllegatoDue);
              allegato.setDataUpload(new Date());
              allegato.setNomeFile(fileNameAllegatoDue);
              allegati.add(allegato);
          }
          if (StringUtils.isNotBlank(fileNameAllegatoTre)) {
              Allegati allegato = new Allegati();
              allegato.setFile(fileAllegatoTre);
              allegato.setDataUpload(new Date());
              allegato.setNomeFile(fileNameAllegatoTre);
              allegati.add(allegato);
          }
      } catch (NoSuchAlgorithmException e) {
          logger.error("Errore nella lettura dell'allegato", e);
      } catch (IOException ioe) {
          logger.error("Errore nella lettura dell'allegato", ioe);
      }
  
      if (allegati.size() &gt; 0) {
          messaggio.setAllegati(allegati);
          entityManager.merge(conversazione);
          entityManager.persist(messaggio);
          /* ERROR DISPLAY IN CONSOLE
          10:33:30,942 INFO  [STDOUT] Hibernate: 
              insert 
              into
                  gm_messaggi
                  (autore, id_conversazione, ts_creazione, ts_invio, ts_ultimo_aggiornamento, destinatario, letto_da_destinatario, mittente, stato, testo, utente_mittente) 
              values
                  (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
          10:33:30,957 INFO  [STDOUT] Hibernate: 
              insert 
              into
                  gm_allegati
                  (ts_upload, file, id_messaggio, nome_file) 
              values
                  (?, ?, ?, ?)
          10:33:30,965 INFO  [STDOUT] 2019-03-05 10:33:30 WARN  JDBCExceptionReporter:233 - SQL Error: 1048, SQLState: 23000
          10:33:30,966 INFO  [STDOUT] 2019-03-05 10:33:30 ERROR JDBCExceptionReporter:234 - Column 'ID_MESSAGGIO' cannot be null
          10:33:50,260 SEVERE [application] javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not insert: [it.racomputer.teso.poste.twsign.conversazioni.entity.Allegati]
          javax.faces.el.EvaluationException: javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not insert: [it.racomputer.teso.poste.twsign.conversazioni.entity.Allegati]         
          */
      } else {
          entityManager.merge(conversazione);
      }
  
      return "ok";
  
  }
  </code></pre>
  
  <p>Messages (Messaggi) entity:</p>
  
  <pre><code>package it.entity;
  
  import java.util.ArrayList;
  import java.util.Date;
  import java.util.List;
  
  import javax.persistence.CascadeType;
  import javax.persistence.Column;
  import javax.persistence.Entity;
  import javax.persistence.FetchType;
  import javax.persistence.JoinColumn;
  import javax.persistence.ManyToOne;
  import javax.persistence.OneToMany;
  import javax.persistence.Table;
  
  import org.hibernate.annotations.Type;
  
  import it.racomputer.seam4ra.auth.entity.AbstractSurrogateKeyEntity;
  import it.racomputer.teso.poste.twsign.enums.EnumProfiloMessaggistica;
  
  @Entity
  @Table(name = "GM_MESSAGGI")
  public class Messaggi extends AbstractSurrogateKeyEntity implements Comparable&lt;Messaggi&gt; {
  
  private static final long serialVersionUID = 7749659591617999027L;
  
  private String autore;
  private Date dataCreazione;
  private Date dataUltimoAggiornamento;
  private Date dataInvio;
  private String stato;
  private String testo;
  private char mittente;
  private char destinatario;
  private String utenteMittente;
  private Conversazioni conversazioni;
  private boolean lettoDaDestinatario;
  private List&lt;Allegati&gt; allegati = new ArrayList&lt;Allegati&gt;();
  
  public Messaggi() {
      super();
  }
  
  public Messaggi(String autore, String stato, String testo, char mittente, String utenteMittente, Conversazioni conversazioni) {
      super();
      this.autore = autore;
      this.dataCreazione = new Date();
      this.dataUltimoAggiornamento = new Date();
      this.dataInvio = new Date();
      this.stato = stato;
      this.testo = testo;
      this.mittente = mittente;
      this.destinatario = EnumProfiloMessaggistica.not(mittente).getValue();
      this.utenteMittente = utenteMittente;
      this.conversazioni = conversazioni;
      this.lettoDaDestinatario = false;
  }
  
  public Messaggi(Messaggi messaggio) {
      super();
      this.autore = messaggio.getAutore();
      this.dataCreazione = messaggio.getDataCreazione();
      this.dataUltimoAggiornamento = messaggio.getDataUltimoAggiornamento();
      this.dataInvio = messaggio.getDataInvio();
      this.stato = messaggio.getStato();
      this.testo = messaggio.getTesto();
      this.mittente = messaggio.getMittente();
      this.destinatario = messaggio.getDestinatario();
      this.utenteMittente = messaggio.getUtenteMittente();
      this.conversazioni = messaggio.getConversazioni();
      this.lettoDaDestinatario = messaggio.isLettoDaDestinatario();
  }
  
  @Column(name="AUTORE", nullable=false, length=45)
  public String getAutore() {
      return autore;
  }
  public void setAutore(String autore) {
      this.autore = autore;
  }
  
  @Column(name="TS_CREAZIONE", nullable=false)
  public Date getDataCreazione() {
      return dataCreazione;
  }
  public void setDataCreazione(Date dataCreazione) {
      this.dataCreazione = dataCreazione;
  }
  
  @Column(name="TS_ULTIMO_AGGIORNAMENTO", nullable=false)
  public Date getDataUltimoAggiornamento() {
      return dataUltimoAggiornamento;
  }
  public void setDataUltimoAggiornamento(Date dataUltimoAggiornamento) {
      this.dataUltimoAggiornamento = dataUltimoAggiornamento;
  }
  
  @Column(name="TS_INVIO", nullable=false)
  public Date getDataInvio() {
      return dataInvio;
  }
  public void setDataInvio(Date dataInvio) {
      this.dataInvio = dataInvio;
  }
  @Override
  public int compareTo(Messaggi m) {
      if (getDataInvio() == null || m.getDataInvio() == null) {
          return 0;
      }
      return getDataInvio().compareTo(m.getDataInvio());
  }
  
  @Column(name="STATO", nullable=false, length=30)
  public String getStato() {
      return stato;
  }
  public void setStato(String stato) {
      this.stato = stato;
  }
  
  @Column(name="TESTO", nullable=false, length=1000)
  public String getTesto() {
      return testo;
  }
  public void setTesto(String testo) {
      this.testo = testo;
  }
  
  @Column(name="MITTENTE", nullable=false, length=1)
  public char getMittente() {
      return mittente;
  }
  public void setMittente(char mittente) {
      this.mittente = mittente;
  }
  
  @Column(name="DESTINATARIO", nullable=false, length=1)
  public char getDestinatario() {
      return destinatario;
  }
  public void setDestinatario(char destinatario) {
      this.destinatario = destinatario;
  }
  
  @Column(name="UTENTE_MITTENTE", nullable=false, length=40)
  public String getUtenteMittente() {
      return utenteMittente;
  }
  public void setUtenteMittente(String utenteMittente) {
      this.utenteMittente = utenteMittente;
  }
  
  @ManyToOne(fetch=FetchType.LAZY,targetEntity=Conversazioni.class)
  @JoinColumn(name="ID_CONVERSAZIONE",nullable=false)
  public Conversazioni getConversazioni() {
      return conversazioni;
  }
  public void setConversazioni(Conversazioni conversazioni) {
      this.conversazioni = conversazioni;
  }
  
  @Type(type = "yes_no")
  @Column(name="LETTO_DA_DESTINATARIO", nullable=false, length=1)
  public boolean isLettoDaDestinatario() {
      return lettoDaDestinatario;
  }
  public void setLettoDaDestinatario(boolean lettoDaDestinatario) {
      this.lettoDaDestinatario = lettoDaDestinatario;
  }   
  public boolean letto(char profiloMessaggistica) {
      if (profiloMessaggistica == getDestinatario() &amp;&amp; !isLettoDaDestinatario()) {
          return false;
      } else {
          return true;
      }
  
  }
  
  @OneToMany(fetch=FetchType.LAZY,cascade=CascadeType.ALL,targetEntity=Allegati.class,mappedBy="messaggi")
  public List&lt;Allegati&gt; getAllegati() {
      return allegati;
  }
  public void setAllegati(List&lt;Allegati&gt; allegati) {
      this.allegati = allegati;
  }
  
  public boolean isMsgMine (char profiloMessaggistica) {
      if (profiloMessaggistica == this.mittente) {
          return true;
      } else {
          return false;
      }
  }
  
  }
  </code></pre>
  
  <p>SuperClass to define primary key generation:</p>
  
  <pre><code>package it.entity;
  
  import java.io.Serializable;
  import javax.persistence.Column;
  import javax.persistence.GeneratedValue;
  import javax.persistence.Id;
  import javax.persistence.MappedSuperclass;
  
  @MappedSuperclass
  public abstract class AbstractSurrogateKeyEntity implements Serializable
  {
      private Long id;
  
      @Id
      @GeneratedValue
      @Column(name="OBJ_ID")
      public Long getId()
      {
          return id;
      }
  
      public void setId(Long id) {
          this.id = id;
      }
  }
  </code></pre>