1

I am trying to map the following table

CREATE TABLE Person (
    p_id varchar(255) not null,
    p_name varchar(255 not null, 
    p_post_code varchar(12) not null,
    primary key (p_id, p_name),
);

Usually when i map an Entity to the above table i would do something like this (for single column primary keys):

private     int     p_id;   
private     String  p_name;
private     String  p_post_code;

@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="p_id")
public Long getPId() {
    return p_id;
}

public void setPId(int p_id) {
    this.p_id = p_id;
}

@Column(name="p_name")
public String getPname() {
    return p_name;
}

public void setPname(String string) {
    this.p_name = string;
}

@Column(name="p_post_code")
public String getPostCode() {
    return p_post_code;
}

public void setPostCode(String string) {
    this.p_post_code = string;
}   

The above works if the primary key is a single column (i.e. p_id) and the value for this column is generated in the database. How would i modify the above to map it so that both p_id and p_name are the primary key.

Also, how would this work, if the composite key is a foreign key in another table.

I am trying to google for some examples but i cant find a simple example and most seem to be using the XML based configuration.

ziggy
  • 15,677
  • 67
  • 194
  • 287
  • You can look here: [stackoverflow] [1]: http://stackoverflow.com/questions/9764204/how-to-create-a-composite-primary-key-hibernate-jpa/9765674#9765674 – Andrey Mar 21 '12 at 13:48

1 Answers1

1

When using composite keys with JPA you need to use an embedded class as an id.

In your case you would have a person class and a primary key class for person:

@entity
public class Person
{
    @EmbeddedId
    private PersonPK key;

    @Column(name="p_post_code", nullable = false)
    private String  p_post_code;

    //....
}

@Embeddable
public class PersonPK
{
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="p_id");
    private Long p_id;

    @Column(name="p_name")
    private String p_name;

    public PersonPK(String name)
    {
        p_name = name;
    }

    //....
}

Using a class for the person's name (so the name is also a foreign key):

@entity
public class Person
{
    @EmbeddedId
    private PersonPK key;

    @MapsId(value="p_name_id")
    @ManyToOne
    @JoinColumn(name = "p_name_id", referencedColumnName = "id")
    private Name p_name;

    @Column(name="p_post_code", nullable = false)
    private     String  p_post_code;

    //....
}

@Embeddable
public class PersonPK
{
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="p_id");
    private Long p_id;

    @Column(name="p_name_id")
    private Long p_name_id;

    public PersonPK(Name name)
    {
        p_name_id = name.getId();
    }

    //....
}

@Entity
public class Name
{
    @Id
    @GeneratedValue(some generation strategy here)
    @Column(name="id")
    private Long id;

    @Column(name="name")
    private String name;

    //....
}
siebz0r
  • 18,867
  • 14
  • 64
  • 107
  • "need to use an embedded class" is inaccurate. Using `@EmbeddedId` is one possible solution. But so is use of `@IdClass`. Simply a matter of taste. – Steve Ebersole Jun 06 '12 at 13:20
  • @SteveEbersole I would agree with you but then I saw this: http://stackoverflow.com/questions/212350/ Now I'm not sure the given answer will work with generated values. – siebz0r Jun 06 '12 at 13:42
  • Stumbling upon this: http://stackoverflow.com/questions/4120414/ Now I'm sure my example will work. Interesting though. :-) – siebz0r Jun 06 '12 at 13:45