Como criar e lidar com a chave primária composta em JPA

108

Eu quero ter versões da mesma entrada de dados. Em outras palavras, desejo duplicar a entrada com outro número de versão.

id - Version será a chave primária.

Como deve ser a aparência da entidade? Como posso duplicá-lo com outra versão?

id Version ColumnA

1   0      Some data
1   1      Some Other data
2   0      Data 2. Entry
2   1      Data
Kayser
fonte
Ao usar a @IdClassanotação, outra dica que descobri é que a @Columnanotação deve ir para os campos da classe Entity ( YourEntityno código de amostra de RohitJan).
KenSV

Respostas:

231

Você pode fazer um Embedded class, que contém suas duas chaves e, em seguida, ter uma referência a essa classe como EmbeddedIdem seu Entity.

Você precisaria das anotações @EmbeddedIde @Embeddable.

@Entity
public class YourEntity {
    @EmbeddedId
    private MyKey myKey;

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

    /** Your getters and setters **/
}
@Embeddable
public class MyKey implements Serializable {

    @Column(name = "Id", nullable = false)
    private int id;

    @Column(name = "Version", nullable = false)
    private int version;

    /** getters and setters **/
}

Outra maneira de realizar esta tarefa é usar @IdClassanotação e lugar tanto o seu idnaquele IdClass. Agora você pode usar @Idanotações normais em ambos os atributos

@Entity
@IdClass(MyKey.class)
public class YourEntity {
   @Id
   private int id;
   @Id
   private int version;

}

public class MyKey implements Serializable {
   private int id;
   private int version;
}
Rohit Jain
fonte
4
É possível usar @Generatedvaluepara Ids por EmbeddedId
Kayser
1
@Kayser. Até onde sei. Não. Você deve definir explicitamente o valor para eles em sua instância de KeyClass e, em seguida, definir essa instância de classe de chave em sua Entidade.
Rohit Jain
@Kayser. @GeneratedValuesó pode ser usado para gerar valores de chave para uma chave primária, não pode gerar combinação para chaves compostas.
Rohit Jain
1
@RohitJain só uma coisa: você realmente não pode tornar a classe incorporada pública (precisa estar em seu próprio arquivo para ser pública)
Lucas
1
@FastEngy Ele ainda pode ser acessado através da Wayback Machine: web.archive.org/web/20170123035517/http://uaihebert.com/… . Parece que este artigo foi substituído por web.archive.org/web/20170202203555/http://uaihebert.com/… e web.archive.org/web/20161014051056/http://uaihebert.com/… que também desapareceram …
radlan
9

A classe MyKey deve implementar Serializablese você estiver usando@IdClass

Swapnil17
fonte
5

Classe chave:

@Embeddable
@Access (AccessType.FIELD)
public class EntryKey implements Serializable {

    public EntryKey() {
    }

    public EntryKey(final Long id, final Long version) {
        this.id = id;
        this.version = version;
    }

    public Long getId() {
        return this.id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getVersion() {
        return this.version;
    }

    public void setVersion(Long version) {
        this.version = version;
    }

    public boolean equals(Object other) {
        if (this == other)
            return true;
        if (!(other instanceof EntryKey))
            return false;
        EntryKey castOther = (EntryKey) other;
        return id.equals(castOther.id) && version.equals(castOther.version);
    }

    public int hashCode() {
        final int prime = 31;
        int hash = 17;
        hash = hash * prime + this.id.hashCode();
        hash = hash * prime + this.version.hashCode();
        return hash;
    }

    @Column (name = "ID")
    private Long id;
    @Column (name = "VERSION")
    private Long operatorId;
}

Classe de entidade:

@Entity
@Table (name = "YOUR_TABLE_NAME")
public class Entry implements Serializable {

    @EmbeddedId
    public EntryKey getKey() {
        return this.key;
    }

    public void setKey(EntryKey id) {
        this.id = id;
    }

    ...

    private EntryKey key;
    ...
}

Como posso duplicá-lo com outra versão?

Você pode desanexar a entidade que recuperou do provedor, alterar a chave de Entrada e então persisti-la como uma nova entidade.

callfarc0de
fonte
É possível definir o id no Entrykey AUTOGENERATED. ou algo parecido @GeneratedValue(strategy = GenerationType.IDENTITY)
Kayser
1
Também estou me perguntando como calcular o hash para 2 chaves primárias longas. Quanto hashe primeno método hashCodeem sala de aula EntryKey, você pode me dizer onde vem essa idéia?
Bruce Sun
1

A classe MyKey (@Embeddable) não deve ter relacionamentos como @ManyToOne

Ranuka
fonte
Por que não? Você viu este exemplo ?
Buhake Sindi