eclipselink(JPA)异常:复合主键@JoinColumn

时间:2011-12-27 02:30:24

标签: java mysql jpa eclipselink

OMG!我一直在想办法解决以下问题。我用Google搜索并尝试了所有可能的方法,但没有运气。

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.<clinit>(DBFactory.java:27)
    ... 2 more


我正在使用netbeans和eclipselink(jpa 2.0)。 我附上了两个表结构。
对于Professor教授,name和departmentID是复合主键,id是自动生成的唯一键,它是评级表的外键。

enter image description here

以下是两个表的java类:

教授

@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<Rating> 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<Rating> getRatingCollection() {
        return ratingCollection;
    }

    public void setRatingCollection(Collection<Rating> 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 && other.professorPK != null) || (this.professorPK != null && !this.professorPK.equals(other.professorPK))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "rateprofessor.database.entity.Professor[ professorPK=" + professorPK + " ]";
    }

}

评分

@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<RatingItem> 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<RatingItem> getRatingItemCollection() {
        return ratingItemCollection;
    }

    public void setRatingItemCollection(Collection<RatingItem> 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 && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "rateprofessor.database.entity.Rating[ id=" + id + " ]";
    }

}

请帮帮我。我真的需要帮助。非常感谢你。

1 个答案:

答案 0 :(得分:1)

问题是JPA不允许您将外键用于不是目标实体ID字段的字段。在您的情况下,Rating有一个professor_id列,它是Id的外键,但Id不是主键 - embeddedId中的name和departmentID。最简单的解决方案是在ID教授内部建立ID字段 - 无论如何,就JPA而言。表本身不需要更改。

这将允许您将professor_id用作教授ID列的外键,并在JPA提供程序中保持可移植性,并仍然使用Name + departmentID作为数据库中的pk。