title: eclipselink (JPA) exception: composite primary key @JoinColumn
body: <p>OMG! i have been figuring out how to solve the following problem. I googled and tried all the possible ways, but no luck.</p>
  
  <pre><code>Caused by: Exception [EclipseLink-30005] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.PersistenceUnitLoadingException
  Exception Description: An exception was thrown while searching for persistence archives with ClassLoader: sun.misc.Launcher$AppClassLoader@93dee9
  Internal Exception: javax.persistence.PersistenceException: Exception [EclipseLink-28018] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.EntityManagerSetupException
  Exception Description: Predeployment of PersistenceUnit [RateProfessorPU] failed.
  Internal Exception: Exception [EclipseLink-7220] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.ValidationException
  Exception Description: The @JoinColumns on the annotated element [field professorId] from the entity class [class rateprofessor.database.entity.Rating] is incomplete. When the source entity class uses a composite primary key, a @JoinColumn must be specified for each join column using the @JoinColumns. Both the name and the referencedColumnName elements must be specified in each such @JoinColumn.
      at org.eclipse.persistence.exceptions.PersistenceUnitLoadingException.exceptionSearchingForPersistenceResources(PersistenceUnitLoadingException.java:127)
      at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactory(PersistenceProvider.java:115)
      at javax.persistence.Persistence.createEntityManagerFactory(Unknown Source)
      at javax.persistence.Persistence.createEntityManagerFactory(Unknown Source)
      at rateprofessor.database.DBFactory.&lt;clinit&gt;(DBFactory.java:27)
      ... 2 more
  </code></pre>
  
  <p><br>
  I'm using netbeans and eclipselink (jpa 2.0).
  I attach the two table structures. 
  <br>
  For Professor Table, the name and departmentID are the composite primary key and the id is the autogenerated unique key, which is the foreign key to the rating table.</p>
  
  <p><img src="https://i.stack.imgur.com/0pEZS.png" alt="enter image description here"></p>
  
  <p><p> 
  Here are the java classes for the two tables:<p>
  <b>Professor</b>
  <br></p>
  
  <pre><code>@Entity
  @Table(name = "professor", catalog = "rateprofessor", schema = "", uniqueConstraints = {
      @UniqueConstraint(columnNames = {"id"})})
  @XmlRootElement
  @NamedQueries({
      @NamedQuery(name = "Professor.findAll", query = "SELECT p FROM Professor p"),
      @NamedQuery(name = "Professor.findByName", query = "SELECT p FROM Professor p WHERE p.professorPK.name = :name"),
      @NamedQuery(name = "Professor.findByDepartmentID", query = "SELECT p FROM Professor p WHERE p.professorPK.departmentID = :departmentID"),
      @NamedQuery(name = "Professor.findByEmail", query = "SELECT p FROM Professor p WHERE p.email = :email"),
      @NamedQuery(name = "Professor.findByPhone", query = "SELECT p FROM Professor p WHERE p.phone = :phone"),
      @NamedQuery(name = "Professor.findByTitle", query = "SELECT p FROM Professor p WHERE p.title = :title"),
      @NamedQuery(name = "Professor.findById", query = "SELECT p FROM Professor p WHERE p.id = :id"),
      @NamedQuery(name = "Professor.findByFirstName", query = "SELECT p FROM Professor p WHERE p.firstName = :firstName"),
      @NamedQuery(name = "Professor.findByLastName", query = "SELECT p FROM Professor p WHERE p.lastName = :lastName")})
  public class Professor implements Serializable {
      private static final long serialVersionUID = 1L;
      @EmbeddedId
      protected ProfessorPK professorPK;
      @Column(name = "email", length = 255)
      private String email;
      @Column(name = "phone", length = 255)
      private String phone;
      @Basic(optional = false)
      @Column(name = "title", nullable = false, length = 255)
      private String title;
      @Basic(optional = false)
      @Column(name = "id", nullable = false)
      private int id;
      @Column(name = "firstName", length = 45)
      private String firstName;
      @Column(name = "lastName", length = 45)
      private String lastName;
      @JoinColumn(name = "departmentID", referencedColumnName = "id", nullable = false, insertable = false, updatable = false)
      @ManyToOne(optional = false)
      private Department department;
      @OneToMany(cascade = CascadeType.ALL, mappedBy = "professorId")
      private Collection&lt;Rating&gt; ratingCollection;
  
      public Professor() {
      }
  
      public Professor(ProfessorPK professorPK) {
          this.professorPK = professorPK;
      }
  
      public Professor(ProfessorPK professorPK, String title, int id) {
          this.professorPK = professorPK;
          this.title = title;
          this.id = id;
      }
  
      public Professor(String name, int departmentID) {
          this.professorPK = new ProfessorPK(name, departmentID);
      }
  
      public ProfessorPK getProfessorPK() {
          return professorPK;
      }
  
      public void setProfessorPK(ProfessorPK professorPK) {
          this.professorPK = professorPK;
      }
  
      public String getEmail() {
          return email;
      }
  
      public void setEmail(String email) {
          this.email = email;
      }
  
      public String getPhone() {
          return phone;
      }
  
      public void setPhone(String phone) {
          this.phone = phone;
      }
  
      public String getTitle() {
          return title;
      }
  
      public void setTitle(String title) {
          this.title = title;
      }
  
      public int getId() {
          return id;
      }
  
      public void setId(int id) {
          this.id = id;
      }
  
      public String getFirstName() {
          return firstName;
      }
  
      public void setFirstName(String firstName) {
          this.firstName = firstName;
      }
  
      public String getLastName() {
          return lastName;
      }
  
      public void setLastName(String lastName) {
          this.lastName = lastName;
      }
  
      public Department getDepartment() {
          return department;
      }
  
      public void setDepartment(Department department) {
          this.department = department;
      }
  
      @XmlTransient
      public Collection&lt;Rating&gt; getRatingCollection() {
          return ratingCollection;
      }
  
      public void setRatingCollection(Collection&lt;Rating&gt; ratingCollection) {
          this.ratingCollection = ratingCollection;
      }
  
      @Override
      public int hashCode() {
          int hash = 0;
          hash += (professorPK != null ? professorPK.hashCode() : 0);
          return hash;
      }
  
      @Override
      public boolean equals(Object object) {
          // TODO: Warning - this method won't work in the case the id fields are not set
          if (!(object instanceof Professor)) {
              return false;
          }
          Professor other = (Professor) object;
          if ((this.professorPK == null &amp;&amp; other.professorPK != null) || (this.professorPK != null &amp;&amp; !this.professorPK.equals(other.professorPK))) {
              return false;
          }
          return true;
      }
  
      @Override
      public String toString() {
          return "rateprofessor.database.entity.Professor[ professorPK=" + professorPK + " ]";
      }
  
  }
  </code></pre>
  
  <p><p>
  Rating
  <br></p>
  
  <pre><code>@Entity
  @Table(name = "rating", catalog = "rateprofessor", schema = "")
  @XmlRootElement
  @NamedQueries({
      @NamedQuery(name = "Rating.findAll", query = "SELECT r FROM Rating r"),
      @NamedQuery(name = "Rating.findById", query = "SELECT r FROM Rating r WHERE r.id = :id"),
      @NamedQuery(name = "Rating.findByDatetime", query = "SELECT r FROM Rating r WHERE r.datetime = :datetime"),
      @NamedQuery(name = "Rating.findByClass1", query = "SELECT r FROM Rating r WHERE r.class1 = :class1"),
      @NamedQuery(name = "Rating.findBySection", query = "SELECT r FROM Rating r WHERE r.section = :section")})
  public class Rating implements Serializable {
      private static final long serialVersionUID = 1L;
      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      @Basic(optional = false)
      @Column(name = "id", nullable = false)
      private Integer id;
      @Basic(optional = false)
      @Column(name = "datetime", nullable = false)
      @Temporal(TemporalType.TIMESTAMP)
      private Date datetime;
      @Column(name = "class", length = 45)
      private String class1;
      @Column(name = "section")
      private Integer section;
      @JoinColumn(name = "user_id", referencedColumnName = "id", nullable = false)
      @ManyToOne(optional = false)
      private User userId;
      @JoinColumn(name = "grade", referencedColumnName = "id")
      @ManyToOne
      private Grade grade;
      @JoinColumn(name = "comment_id", referencedColumnName = "id", nullable = false)
      @ManyToOne(optional = false)
      private Comment commentId;
      @JoinColumn(name = "professor_id", referencedColumnName = "id", nullable = false)
      @ManyToOne(optional = false)
      private Professor professorId;
      @OneToMany(cascade = CascadeType.ALL, mappedBy = "rating")
      private Collection&lt;RatingItem&gt; ratingItemCollection;
  
      public Rating() {
      }
  
      public Rating(Integer id) {
          this.id = id;
      }
  
      public Rating(Integer id, Date datetime) {
          this.id = id;
          this.datetime = datetime;
      }
  
      public Integer getId() {
          return id;
      }
  
      public void setId(Integer id) {
          this.id = id;
      }
  
      public Date getDatetime() {
          return datetime;
      }
  
      public void setDatetime(Date datetime) {
          this.datetime = datetime;
      }
  
      public String getClass1() {
          return class1;
      }
  
      public void setClass1(String class1) {
          this.class1 = class1;
      }
  
      public Integer getSection() {
          return section;
      }
  
      public void setSection(Integer section) {
          this.section = section;
      }
  
      public User getUserId() {
          return userId;
      }
  
      public void setUserId(User userId) {
          this.userId = userId;
      }
  
      public Grade getGrade() {
          return grade;
      }
  
      public void setGrade(Grade grade) {
          this.grade = grade;
      }
  
      public Comment getCommentId() {
          return commentId;
      }
  
      public void setCommentId(Comment commentId) {
          this.commentId = commentId;
      }
  
      public Professor getProfessorId() {
          return professorId;
      }
  
      public void setProfessorId(Professor professorId) {
          this.professorId = professorId;
      }
  
      @XmlTransient
      public Collection&lt;RatingItem&gt; getRatingItemCollection() {
          return ratingItemCollection;
      }
  
      public void setRatingItemCollection(Collection&lt;RatingItem&gt; ratingItemCollection) {
          this.ratingItemCollection = ratingItemCollection;
      }
  
      @Override
      public int hashCode() {
          int hash = 0;
          hash += (id != null ? id.hashCode() : 0);
          return hash;
      }
  
      @Override
      public boolean equals(Object object) {
          // TODO: Warning - this method won't work in the case the id fields are not set
          if (!(object instanceof Rating)) {
              return false;
          }
          Rating other = (Rating) object;
          if ((this.id == null &amp;&amp; other.id != null) || (this.id != null &amp;&amp; !this.id.equals(other.id))) {
              return false;
          }
          return true;
      }
  
      @Override
      public String toString() {
          return "rateprofessor.database.entity.Rating[ id=" + id + " ]";
      }
  
  }
  </code></pre>
  
  <p>Please help me. I seriously need help. Thanks you so much.</p>