如何在 JPA 中创建和处理复合主键

Posted

技术标签:

【中文标题】如何在 JPA 中创建和处理复合主键【英文标题】:How to create and handle composite primary key in JPA 【发布时间】:2012-10-13 12:47:23 【问题描述】:

我想拥有来自同一数据条目的版本。换句话说,我想用另一个版本号复制条目。

id - Version 将是主键。

实体应该是什么样子?如何将其复制到另一个版本?

id Version ColumnA

1   0      Some data
1   1      Some Other data
2   0      Data 2. Entry
2   1      Data

【问题讨论】:

当使用@IdClass 注释时,我发现的另一个提示是@Column 注释应该进入实体类的字段(YourEntity 在 RohitJan 的示例代码中)。 【参考方案1】:

MyKey 类 (@Embeddable) 不应有类似 @ManyToOne 的任何关系

【讨论】:

为什么不呢?你看过这个example吗?【参考方案2】:

您可以创建一个 Embedded class,其中包含您的两个密钥,然后在您的 Entity 中将该类作为 EmbeddedId 的引用。

您需要@EmbeddedId@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 **/


实现此任务的另一种方法是使用@IdClass 注释,并将您的id 放在那个IdClass 中。现在您可以在两个属性上使用普通的@Id 注释

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

【讨论】:

EmbeddedId 是否可以使用@Generatedvalue 作为Id @Kayser。据我所知。不,您必须在 KeyClass 实例中显式设置它们的值,然后在您的实体中设置该键类实例。 @Kayser。 @GeneratedValue只能用于生成主键的键值,不能生成复合键的组合。 @Kayser。请参阅 JPA 2.0 规范的 Section - 11.1.17 GeneratedValue Annotation。它清楚地表明,@GeneratedValue 只能与简单的主键一起使用。 @RohitJain 只有一件事:您实际上不能将嵌入式类公开(需要在其自己的文件中才能公开)【参考方案3】:

关键类:

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

实体类:

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

如何将其复制到另一个版本?

您可以分离从提供者检索到的实体,更改 Entry 的键,然后将其作为新实体持久化。

【讨论】:

是否可以在Entrykey AUTOGENERATED 中定义id。或者类似的东西@GeneratedValue(strategy = GenerationType.IDENTITY) 我也想知道如何计算 2 个长主键的哈希值。至于EntryKey类中hashCode方法中的hashprime,你能告诉我这个想法是从哪里来的吗?【参考方案4】:

如果你使用@IdClass,MyKey 类必须实现Serializable

【讨论】:

以上是关于如何在 JPA 中创建和处理复合主键的主要内容,如果未能解决你的问题,请参考以下文章

使用 Quarkus 的 JPA 中的复合主键是不是可能?

SpringData JPA复合主键

JPA复合主键[重复]

jpa复合主键表不返回值

jpa 复合主键并可与唯一键连接

具有复合主键查询的 JPA COUNT 不起作用