title: JPA - Hibernate ManyToMany relationship save
body: <p>Hey people I've been searching over the internet for the following problem without success...</p>
  
  <p>Well... I'm testing whit Hibernate and JPA annotations, I've developed a usual user case ManyToMany relationship. I've tried to save a new User with existing Groups and the test case throws an exception, see test code and exception below*:</p>
  
  <p>pd. looking at the queries the weird behavior in this case is that it's supossed that the logical path in this test the first method look up persisted groups and since they exit already save the new user record in its table and insert the new records in the link table.. but It is like Hibernate assume that Groups are new records and try to insert them in group table and of course this is throwing the duplicate exception... but I haven't figured it out yet... </p>
  
  <p>What can I do? What am I doing wrong here ?</p>
  
  <p>Thanks in advance.</p>
  
  <pre><code>@Test
      public void guardarUsuario(){
          assertThat(servicio, is(notNullValue()));
          Usuario u = new Usuario();
          u.setNombre("Elsy");
          u.setApellido("Cadenas");
          u.setCedula("4375792");     
  
          List&lt;Grupo&gt; grupos = servicio.buscarGrupos();
  
          u.getGrupos().addAll(grupos);
  
          servicio.guardarUsuario(u);
  
  
      }
  
  Hibernate: select grupo0_.nombre as nombre1_, grupo0_.descripcion as descripc2_1_ from public.grupo grupo0_
  Hibernate: select usuarios0_.idgrupo as idgrupo1_1_, usuarios0_.idusuario as idusuario1_, usuario1_.cedula as cedula0_0_, usuario1_.apellido as apellido0_0_, usuario1_.nombre as nombre0_0_, usuario1_.version as version0_0_ from usuario_grupo usuarios0_ inner join public.usuario usuario1_ on usuarios0_.idusuario=usuario1_.cedula where usuarios0_.idgrupo=?
  Hibernate: select usuarios0_.idgrupo as idgrupo1_1_, usuarios0_.idusuario as idusuario1_, usuario1_.cedula as cedula0_0_, usuario1_.apellido as apellido0_0_, usuario1_.nombre as nombre0_0_, usuario1_.version as version0_0_ from usuario_grupo usuarios0_ inner join public.usuario usuario1_ on usuarios0_.idusuario=usuario1_.cedula where usuarios0_.idgrupo=?
  Hibernate: select usuario0_.cedula as cedula0_0_, usuario0_.apellido as apellido0_0_, usuario0_.nombre as nombre0_0_, usuario0_.version as version0_0_ from public.usuario usuario0_ where usuario0_.cedula=?
  Hibernate: insert into public.usuario (apellido, nombre, version, cedula) values (?, ?, ?, ?)
  Hibernate: insert into public.grupo (descripcion, nombre) values (?, ?)
  Hibernate: insert into public.grupo (descripcion, nombre) values (?, ?)
  2469 [main] WARN  org.hibernate.util.JDBCExceptionReporter  - SQL Error: 0, SQLState: 23505
  2469 [main] ERROR org.hibernate.util.JDBCExceptionReporter  - Batch entry 0 insert into public.grupo (descripcion, nombre) values ('usuarios', 'USUARIO') was aborted.  Call getNextException to see the cause.
  2469 [main] WARN  org.hibernate.util.JDBCExceptionReporter  - SQL Error: 0, SQLState: 23505
  2469 [main] ERROR org.hibernate.util.JDBCExceptionReporter  - ERROR: duplicate key value violates unique constraint "pk_grupo"
  </code></pre>
  
  <p>User.class</p>
  
  <pre><code>@Entity()
  @Table(name = "usuario", schema = "public")
  @NamedQuery(name = "Usuario.findByCedula", query = "select u from Usuario u where u.cedula = :cedula")
  public class Usuario implements Serializable {
  
      /**
       * 
       */
      private static final long serialVersionUID = 1L;
      private String nombre;
      private String apellido;
      @Id
      @Column(length = 8)
      private String cedula;
      @Version
      private Integer version;
      @JoinTable(name = "usuario_grupo", joinColumns = { @JoinColumn(name = "idusuario", referencedColumnName = "cedula") }, inverseJoinColumns = { @JoinColumn(name = "idgrupo", referencedColumnName = "nombre") })
      @ManyToMany(cascade =  { CascadeType.PERSIST }, fetch = FetchType.LAZY)
      private Set&lt;Grupo&gt; grupos = new HashSet&lt;Grupo&gt;();
  
      Constructors... Getters and setters...
  
      @Override
      public int hashCode() {
          final int prime = 31;
          int result = 1;
          result = prime * result + ((cedula == null) ? 0 : cedula.hashCode());
          return result;
      }
  
      @Override
      public boolean equals(Object obj) {
          if (this == obj)
              return true;
          if (obj == null)
              return false;
          if (getClass() != obj.getClass())
              return false;
          Usuario other = (Usuario) obj;
          if (cedula == null) {
              if (other.cedula != null)
                  return false;
          } else if (!cedula.equals(other.cedula))
              return false;
          return true;
      }
  
      public void addGrupo(Grupo g) {
          if (!getGrupos().contains(g)) {
              getGrupos().add(g);
          }
          if (!g.getUsuarios().contains(this)) {
              g.getUsuarios().add(this);
          }
      }
  </code></pre>
  
  <p>Group.class</p>
  
  <pre><code>@Entity
  @Table(name="grupo", schema="public")
  public class Grupo implements Serializable{
  
  
      private static final long serialVersionUID = 1L;
      @Id
      private String nombre;
      private String descripcion;
      @JoinTable(name="usuario_grupo", joinColumns={@JoinColumn(name="idgrupo")}, inverseJoinColumns=@JoinColumn(name="idusuario"))
      @ManyToMany(cascade={CascadeType.PERSIST}, fetch=FetchType.EAGER)
      private Set&lt;Usuario&gt; usuarios = new HashSet&lt;Usuario&gt;(); 
  
      Constructors... Getters and Setters...
  
      @Override
      public int hashCode() {
          final int prime = 31;
          int result = 1;
          result = prime * result
                  + ((descripcion == null) ? 0 : descripcion.hashCode());
          result = prime * result + ((nombre == null) ? 0 : nombre.hashCode());
          return result;
      }
  
      @Override
      public boolean equals(Object obj) {
          if (this == obj)
              return true;
          if (obj == null)
              return false;
          if (getClass() != obj.getClass())
              return false;
          Grupo other = (Grupo) obj;
          if (descripcion == null) {
              if (other.descripcion != null)
                  return false;
          } else if (!descripcion.equals(other.descripcion))
              return false;
          if (nombre == null) {
              if (other.nombre != null)
                  return false;
          } else if (!nombre.equals(other.nombre))
              return false;
          return true;
      }
  }
  </code></pre>
  
  <p>SQL:</p>
  
  <pre><code>USER Table
  
  
  -- Table: usuario
  
  -- DROP TABLE usuario;
  
  CREATE TABLE usuario
  (
    nombre character varying(50),
    apellido character varying(50),
    cedula character varying(8) NOT NULL,
    "version" integer,
    CONSTRAINT pk_usuario PRIMARY KEY (cedula)
  )
  WITH (
    OIDS=FALSE
  );
  ALTER TABLE usuario OWNER TO postgres;
  </code></pre>
  
  <p>GROUP Table</p>
  
  <pre><code>-- Table: grupo
  
  -- DROP TABLE grupo;
  
  CREATE TABLE grupo
  (
    nombre character varying(20) NOT NULL,
    descripcion character varying(50),
    CONSTRAINT pk_grupo PRIMARY KEY (nombre)
  )
  WITH (
    OIDS=FALSE
  );
  ALTER TABLE grupo OWNER TO postgres;
  </code></pre>
  
  <p>Link Table</p>
  
  <pre><code>-- Table: usuario_grupo
  
  -- DROP TABLE usuario_grupo;
  
  CREATE TABLE usuario_grupo
  (
    idusuario character varying(8) NOT NULL,
    idgrupo character varying(20) NOT NULL,
    CONSTRAINT pk_id_grupo PRIMARY KEY (idusuario, idgrupo),
    CONSTRAINT fk_miembro_grupo FOREIGN KEY (idgrupo)
        REFERENCES grupo (nombre) MATCH SIMPLE
        ON UPDATE NO ACTION ON DELETE NO ACTION,
    CONSTRAINT fk_miembro_usuario FOREIGN KEY (idusuario)
        REFERENCES usuario (cedula) MATCH SIMPLE
        ON UPDATE NO ACTION ON DELETE NO ACTION
  )
  WITH (
    OIDS=FALSE
  );
  ALTER TABLE usuario_grupo OWNER TO postgres;
  </code></pre>