无法在 Hibernate/JPA/Spring 引导项目中创建包含 3 个字段的复合 PK
Unable to create a composite PK with 3 fields in Hibernate/JPA/Spring boot project
目标是建立一个连接 table (FormComponent),它将表单(通过 formId)绑定到组件 (componentId),并带有额外的 sortOrder 列。所有三列一起形成一个唯一的复合主键。
如果我只在我的@Embeddable class 中定义 formId 和 componentId,我的实现确实有效,但这不允许我有重复项(一个表单可能多次具有相同的组件)。
如果我将 sortOrder-column 添加到 PK 并加入 table class,我会收到以下错误:
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
复合PKclass:
@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;
}
加入tableclass:
@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。
项目使用Springboot 2.5.1.
为了回答我自己的问题(睡个好觉之后),问题是在 FormComponent class 中定义了 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 table 转储(来自 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);
目标是建立一个连接 table (FormComponent),它将表单(通过 formId)绑定到组件 (componentId),并带有额外的 sortOrder 列。所有三列一起形成一个唯一的复合主键。
如果我只在我的@Embeddable class 中定义 formId 和 componentId,我的实现确实有效,但这不允许我有重复项(一个表单可能多次具有相同的组件)。
如果我将 sortOrder-column 添加到 PK 并加入 table class,我会收到以下错误:
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
复合PKclass:
@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;
}
加入tableclass:
@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。
项目使用Springboot 2.5.1.
为了回答我自己的问题(睡个好觉之后),问题是在 FormComponent class 中定义了 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 table 转储(来自 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);