Reputation:
I have includes the error that I am getting while building JPA classes to the table schema shown...can anyone guide me on how to solve this error. And also how to make composite keys when one of the key is actually a foreign key. Whats wrong in my annotations ?
Error
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"
Table Schema
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) );
Classes
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; } }
Try with Composite key also failed and gave the same error.
Alot of internet search does not lead to any solution yet.
Upvotes: 4
Views: 5810
Reputation: 21145
The problem is 2 fold. One problem is with personId mapping within SpecialtyPK. @Column is used for basic mappings; you need to specify the column to use for joining using the @JoinColumn annotation.
The second and more important is that primary key classes should not contain relationships - it doesn't matter if it is embeddable defined as a primary key class, it should only contain basic mappings or other primary keys (derrived IDs are allows in JPA 2.0, which means key classes can be nested). So you will need a SpecialtyPK class that has personId with a type of 'int'. You can then specify a ManyToOne mapping within Specialty and add the @MapsId to point it at the int, so that you only need to set the relationship and not manage the basic mapping within the embeddable.
@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
..
or you can just remove the embeddedId and mark the photographer as the id.
Upvotes: 0
Reputation: 34657
Looks to me like you have a composite primary key but your telling JPA, through annotations that you have an embedded primary key. Like I tell everyone who is coming to a project for the first time:
Get the simplest thing working first, without giving heed to efficiency and optimise as client needs dictate.
Premature optimisation is the root of many-a-software problem.
Upvotes: 1