JPA:OpenJPA:类型指定的id类与类的主键字段不匹配

时间:2012-11-25 05:15:59

标签: java hibernate jpa persistence

我已经包含了在将JPA类构建到所显示的表模式时所获得的错误...任何人都可以指导我如何解决此错误。以及当其中一个键实际上是外键时如何制作复合键。我的注释有什么问题?

错误

 org.apache.openjpa.util.MetaDataException: The id class specified by type "class Specialty" does not match the primary key fields of the class. 
Make sure your identity class has the same primary keys as your persistent type, including pk field types. Mismatched property: "personId"

表格架构

create table Location(
  id int primary key,
  city varchar(255),
  state varchar(100),
  country varchar(255)
);
create table Person(
  id int primary key,
  name varchar(100)
);
create table Photographer(
  id int primary key references Person(id) on update cascade on delete cascade,
  livesIn int not null references Location(id) on update cascade on delete no action
);
create table Specialty(
  photographer int references Photographer(id) on update cascade on delete cascade,
  type enum('portrait','landscape','sport'),
  primary key(photographer, type)
);
create table Photo(
  id int primary key,
  takenAt timestamp not null,
  takenBy int references Photographer(id) on update cascade on delete no action,
  photographedAt int references Location(id) on update cascade on delete no action,
  type enum('portrait','landscape','sport')
);
create table Appearance(
  shows int references Person(id) on update cascade on delete cascade,
  isShownIn int references Photo(id) on update cascade on delete cascade,
  primary key(shows, isShownIn)
);

课程

Person.java

@Entity
public class Person implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private String name;


Location.java

@Entity
public class Location implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private String city;

    private String state;

    private String country;


Photographer.java

@Entity
public class Photographer implements Serializable {

    @Id
    @ManyToOne
    @Column(name = "id")
    private Person personId;

    @ManyToOne
    @Column(name = "livesIn")
    private Location livesIn;

Photo.java

@Entity
public class Photo implements Serializable {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    // Foreign Key
    @ManyToOne
    @JoinColumn(name = "takenBy")
    private Photographer takenBy;

    // Foreign Key
    @ManyToOne
    @JoinColumn(name = "photographedAt")
    private Location photographedAt;

    @Basic(optional = false)
    @Column(name = "takenAt", insertable = false, updatable = false)
    @Temporal(TemporalType.DATE)
    private Date takenAt;

    @Enumerated(EnumType.STRING)
    private PhotoType type;

PhotoType

 
public enum PhotoType {
    PORTRAIT("portrait"), LANDSCAPE("landscape"), SPORT("sport");
    private String type;

    PhotoType(String type) {
        this.type = type;
    }

    public String getType() {
        return type;
    }

}

Specialty.java

 
import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;

@Entity
public class Specialty implements Serializable {

    @EmbeddedId
    protected SpecialtyPK specialtyPK;

    public Specialty() {
        super();
    }

    public Specialty(SpecialtyPK specialtyPK) {
        super();
        this.specialtyPK = specialtyPK;
    }

}

@Embeddable
class SpecialtyPK implements Serializable {

    @ManyToOne
    @Column(name = "id")
    private Photographer personId;

    @Enumerated(EnumType.STRING)
    private PhotoType type;

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((personId == null) ? 0 : personId.hashCode());
        result = prime * result + ((type == null) ? 0 : type.hashCode());
        return result;
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        SpecialtyPK other = (SpecialtyPK) obj;
        if (personId == null) {
            if (other.personId != null)
                return false;
        } else if (!personId.equals(other.personId))
            return false;
        if (type != other.type)
            return false;
        return true;
    }

    public SpecialtyPK() {
        super();
        // TODO Auto-generated constructor stub
    }

    public SpecialtyPK(Photographer personId, PhotoType type) {
        super();
        this.personId = personId;
        this.type = type;
    }

}

尝试使用Composite键也失败并给出了同样的错误。

很多互联网搜索还没有找到任何解决方案。

2 个答案:

答案 0 :(得分:1)

在我看来,你有一个composite primary key但是你告诉JPA,通过注释你有一个embedded primary key。就像我告诉所有第一次参加项目的人一样:

  

让最简单的事情先行,不要注意效率,并根据客户的需求进行优化。

过早优化是许多软件问题的根源。

答案 1 :(得分:0)

问题是2倍。一个问题是在SpecialtyPK中使用personId映射。 @Column用于基本映射;您需要使用@JoinColumn批注指定要用于连接的列。

第二个也是更重要的是主键类不应该包含关系 - 如果它是可嵌入定义为主键类并不重要,它应该只包含基本映射或其他主键(来自内存的ID) JPA 2.0,这意味着可以嵌套关键类)。所以你需要一个具有类型为'int'的personId的SpecialtyPK类。然后,您可以在Specialty中指定ManyToOne映射并添加@MapsId以将其指向int,这样您只需设置关系而不管理嵌入中的基本映射。

@Entity
public class Specialty implements Serializable {

    @EmbeddedId
    protected SpecialtyPK specialtyPK;

    @MapsId("personId")
    protected Photographer photographer;
..

class SpecialtyPK implements Serializable {

    @Column(name = "id")
    private int personId;//defaults to basic

..

或者你可以删除embeddedId并将摄影师标记为id。