Cómo crear y manejar una clave primaria compuesta en JPA

108

Quiero tener versiones de la misma entrada de datos. En otras palabras, quiero duplicar la entrada con otro número de versión.

id - Version será la clave principal.

¿Cómo debería verse la entidad? ¿Cómo puedo duplicarlo con otra versión?

id Version ColumnA

1   0      Some data
1   1      Some Other data
2   0      Data 2. Entry
2   1      Data
Kayser
fuente
Al usar la @IdClassanotación, otro consejo que encontré es que la @Columnanotación debe ir a los campos de la clase Entity ( YourEntityen el código de muestra de RohitJan).
KenSV

Respuestas:

231

Puede hacer un Embedded class, que contiene sus dos claves, y luego tener una referencia a esa clase como EmbeddedIden su Entity.

Necesitaría las anotaciones @EmbeddedIdy @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 **/
}

Otra forma de lograr esta tarea es usar la @IdClassanotación y colocar ambos iden ella IdClass. Ahora puede usar la @Idanotación normal en ambos 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
fuente
4
¿Es posible utilizar @Generatedvaluepara la identificación de por EmbeddedId
Kayser
1
@Kayser. Por lo que sé. No. Debe establecer explícitamente el valor para ellos en su instancia de KeyClass, y luego establecer esa instancia de clase de clave en su Entidad.
Rohit Jain
@Kayser. @GeneratedValuesolo se puede utilizar para generar valores de clave para una clave principal, no puede generar combinaciones para claves compuestas.
Rohit Jain
1
@RohitJain solo una cosa: en realidad no se puede hacer pública la clase incrustada (debe estar en su propio archivo para ser pública)
Lucas
1
@FastEngy Todavía se puede acceder a través de Wayback Machine: web.archive.org/web/20170123035517/http://uaihebert.com/… . Parece que este artículo es reemplazado por web.archive.org/web/20170202203555/http://uaihebert.com/… y web.archive.org/web/20161014051056/http://uaihebert.com/… que también desapareció …
radlan
9

La clase MyKey debe implementarse Serializablesi está utilizando@IdClass

Swapnil17
fuente
5

Clase clave:

@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;
}

Clase de entidad:

@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;
    ...
}

¿Cómo puedo duplicarlo con otra versión?

Puede separar la entidad que se recuperó del proveedor, cambiar la clave de Entrada y luego conservarla como una nueva entidad.

callfarc0de
fuente
Es posible definir la identificación en Entrykey AUTOGENERATED. o algo así @GeneratedValue(strategy = GenerationType.IDENTITY)
Kayser
1
También me pregunto cómo calcular el hash para 2 claves primarias largas. En cuanto a hashy primeen el método hashCodeen la clase EntryKey, me puede decir donde esta idea proviene de?
Bruce Sun
1

La clase MyKey (@Embeddable) no debe tener relaciones como @ManyToOne

Ranuka
fuente
Por qué no? ¿Ha mirado este ejemplo ?
Buhake Sindi