PrimaryKey, ForeignKey and Unique With JPA

5

I have the following situation:

  • Entity Student (id and so on)
  • Evaluation Entity (id and others)
  • Entity NoteEvaluationAlumni (assessmentId, studentId)
  • I want to transform the evaluation attributes, alunoId that have relations with entities 1 and 2 in PrimaryKey and that are Unique.

    What is the best way for this mapping?

    I've checked a few ways but be in doubt about how to actually use them.

        
    asked by anonymous 13.08.2014 / 16:23

    2 answers

    1

    1- First you need to map the entity Student

    @Entity
    @Table(name="Aluno") // Eu sempre informo o 'name', mania minha
    public class Aluno implements Serializable {
      @Id
      @Column(name = "id")
      private java.lang.Long id; 
    
      // Demais campos...
    }
    

    2 - Mapping Entity Evaluating

    @Entity
    @Table(name="Avaliacao")
    public class Avaliacao implements Serializable {
      @Id
      @Column(name = "id")
      private java.lang.Long id; 
    
      // Demais campos...
    }
    

    3 - Map the entity NotaAvaliacao

    Before posting the example, it is not always necessary to map these many-to-many. I decided to map it because it has information (which I believe to be the student's grade).

    @Entity
    @Table(name="NotaAvaliacaoAluno")
    public class NotaAvaliacaoAluno implements Serializable {
      @Id
      @ManyToOne(fetch = FetchType.LAZY)
      @JoinColumn( name = "avaliacaoId", referencedColumnName="id")
      private Avaliacao avaliacao; 
    
      @Id
      @Column(name = "alunoId")
      @JoinColumn(name = "alunoId", referencedColumnName="id")
      private Aluno aluno; 
    
      // Demais campos...
    }
    

    4 - Now we return to the student class and include

     @OneToMany(fetch=fetchType.LAZY, mappedBy="aluno")
     private List<NotaAvaliacaoAluno> notasValiacaoAlunoList;
    

    Ready.

    Q.: As I do not know your model, I believe it is the most appropriate and analyze my answer, understand what I suggested and adapt to your case.

        
    13.08.2014 / 18:18
    0

    In all cases you will need a composite key (since on the side of the bank the PK is composed the JPA should keep this template).

    This can be done in two ways:

  • ID Entity + @IdClass

    public class NotaAvaliacaoAlunoPK implements Serializable { 
        private Integer idAluno;
        private Integer idAvaliacao;
        // Outros campos da PK se existirem
    
        // Getters & setters, equals e hashCode
    }
    
    @Entity 
    @IdClass(value=NotaAvaliacaoAlunoPK.class)
    public class NotaAvaliacaoAluno implements Serializable { 
        @Id @Column(name="ID_ALUNO")
        private Integer idAluno;
        @Id @Column(name="ID_AVALIACAO")
        private Integer idAvaliacao;
        // Outros campos da PK se existirem
        @Column
        private String outroCampoQualquer;
    
        // Getters & setters
    }
    
  • Multiple columns of IDs + @EmbeddedId

    @Embeddable
    public class NotaAvaliacaoAlunoPK implements Serializable { 
        @Column(name="ID_ALUNO")
        private Integer idAluno;
        @Column(name="ID_AVALIACAO")
        private Integer idAvaliacao;
    
        // Getters & setters, equals e hashCode
    }
    
    @Entity 
    public class NotaAvaliacaoAluno implements Serializable { 
        @EmbeddedId
        private NotaAvaliacaoAlunoPK id;
        @Column
        private String outroCampoQualquer;
    }
    
  • The second decision is to know who sends on the Primary Key, whether it is the PK fields directly or whether they are the relationships with Aluno and Avaliacao .

  • Primary key fields, make relationships do not update the database:

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="ID_ALUNO", insertable=false, updatable=false)
    private Aluno aluno;
    
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="ID_AVALIACAO", insertable=false, updatable=false)
    private Avaliacao avaliacao;
    
  • If the relationships are, make sure that the PK fields do not update the database and that the entities of the relationships do (through @PrimaryKeyJoinColumn ):

    @Column(name="ID_ALUNO", insertable=false, updatable=false)
    private Integer idAluno;
    @Column(name="ID_AVALIACAO", insertable=false, updatable=false)
    private Integer idAvaliacao;
    
    @ManyToOne(fetch=FetchType.LAZY)
    @PrimaryKeyJoinColumn(name="ID_ALUNO")
    private Aluno aluno;
    
    @ManyToOne(fetch=FetchType.LAZY)
    @PrimaryKeyJoinColumn(name="ID_AVALIACAO")
    private Avaliacao avaliacao;
    
  • See that I did not even merit Element Collections to make it even more complicated but the use of collections may be a good idea if the evaluation note values do not make sense outside the context of the parent object.

    On the "most correct" way of modeling a problem, there is no easy answer. It may be that in your application it makes more sense to manipulate ids directly, it might make more sense to build an ID object. Perhaps it makes more sense to deal with PK values directly (by inserting student ids and evaluations), perhaps the opposite makes sense (look up the Pupil object and the whole Evaluation object from the database and set up the relationships).

    And there are still those who prefer to appeal to a good old map:

    @OneToMany(mappedBy="aluno")
    @MapKeyColumn(name="ID_AVALIACAO")
    private Map<Integer, NotaAvaliacao> notas;
    
        
    13.08.2014 / 18:50