首页 > 解决方案 > 无法在 Hibernate/JPA/Spring boot 项目中创建具有 3 个字段的复合 PK

问题描述

目标是拥有一个连接表(FormComponent),它将一个表单(通过 formId)绑定到一个带有额外列 sortOrder 的组件(componentId)。所有三列一起形成一个唯一的复合主键。

如果我只在 @Embeddable 类中定义 formId 和 componentId,我的实现确实有效,但这不允许我有重复项(一个表单可能多次具有相同的组件)。

如果我将 sortOrder-column 添加到 PK 并加入表类,我会收到以下错误:

    java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:132
    Caused by: org.springframework.beans.factory.BeanCreationException at AbstractAutowireCapableBeanFactory.java:1786
        Caused by: javax.persistence.PersistenceException at AbstractEntityManagerFactoryBean.java:421
            Caused by: org.hibernate.MappingException at PersistentClass.java:862

复合PK类:

@EqualsAndHashCode
@AllArgsConstructor
@Getter
@Embeddable
public class FormComponentId implements Serializable {
    @Column(name = "form_id")
    private Long formId;
    @Column(name = "component_id")
    private Long componentId;
    @Column(name = "sort_order")
    private Long sortOrder;
}

连接表类:

@Data
@Getter
@Setter
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "form_component")
public class FormComponent {
    @EmbeddedId
    private FormComponentId id;
    @ManyToOne(fetch = FetchType.EAGER)
    @MapsId("formId")
    private Form            form;
    @ManyToOne(fetch = FetchType.EAGER)
    @MapsId("componentId")
    private Component       component;
    private Long            sortOrder;
}

如果我正确理解了文档,我应该能够定义一个超过 2 列的复合 PK。

该项目使用Spring boot 2.5.1。

标签: spring-data-jpahibernate-mapping

解决方案


要回答我自己的问题(睡个好觉之后),问题是在 FormComponent 类中定义了 sortOrder 列。

有了这个 form_component 被正确创建:

@Data
@Getter
@Setter
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "form_component")
public class FormComponent {
    @EmbeddedId
    private FormComponentId id;
    @ManyToOne(fetch = FetchType.EAGER)
    @MapsId("formId")
    private Form            form;
    @ManyToOne(fetch = FetchType.EAGER)
    @MapsId("componentId")
    private Component       component;
}

form_component 表转储(来自 MariaDB):

CREATE TABLE form_component (
  sort_order bigint(20) NOT NULL,
  component_id bigint(20) NOT NULL,
  form_id bigint(20) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

ALTER TABLE form_component
  ADD PRIMARY KEY (component_id,form_id,sort_order),
  ADD KEY FK1d1gjrgj8elln6irre9vj45e (form_id);

ALTER TABLE form_component
  ADD CONSTRAINT FK1d1gjrgj8elln6irre9vj45e FOREIGN KEY (form_id) REFERENCES form (id),
  ADD CONSTRAINT FKlbpvqdblh0i147fqctd7dhs6a FOREIGN KEY (component_id) REFERENCES component (id);

推荐阅读