使用额外的列 Jpa 保存多对多关系
Save Many-to-many relation with extra columns Jpa
我就是这种情况。我有三个实体:Form、FormComponent 和 FormComponentJoin。
它是与额外列的多对多关系。
我想通过一次调用 FormRepository save() 方法来保存一个表单实体及其所有子实体,但它不起作用。
这是错误消息:
错误由以下原因引起:org.hibernate.TransientPropertyValueException:对象引用未保存的瞬态实例 - 在刷新之前保存瞬态实例
这些是我的实体:
@Data
@Entity
@Table(name = "form")
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class Form implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid")
private String id;
private String name;
@OneToMany(mappedBy = "form", cascade = { CascadeType.PERSIST, CascadeType.MERGE }, orphanRemoval = true)
@NotFound(action = NotFoundAction.IGNORE)
@Singular
private List<FormComponentJoin> formComponentJoin = new ArrayList<>();
}
@Data
@EqualsAndHashCode
@Entity
@Table(name = "form_component")
@AllArgsConstructor(suppressConstructorProperties = true)
@NoArgsConstructor
public class FormComponent implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid")
private String id;
@JsonIgnore
@OneToMany(mappedBy = "formComponent", cascade = CascadeType.ALL, orphanRemoval = true)
@NotFound(action = NotFoundAction.IGNORE)
private List<FormComponentJoin> formComponentJoin = new ArrayList<>();
@ManyToOne
@JsonIgnore
private FormComponent parent;
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
@Singular
private List<FormComponent> children;
private String value;
}
@Entity
@Table(name = "form_component_join")
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class FormComponentJoin implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid")
private String id;
@ManyToOne
@JoinColumn(name = "form_id", referencedColumnName = "id")
@NotFound(action = NotFoundAction.IGNORE)
@JsonIgnore
private Form form;
@ManyToOne
@JoinColumn(name = "form_component_id", referencedColumnName = "id")
@NotFound(action = NotFoundAction.IGNORE)
private FormComponent formComponent;
@Column(name = "position")
private int pos;
}
@Repository
@Transactional(readOnly = true)
public interface FormRepository extends PagingAndSortingRepository<Form, String> {
}
为了进行测试,我使用了 CommandLineRunner:
@Bean
public CommandLineRunner initDatabase(FormRepository formRepository) {
return (args) -> {
FormComponent formComponent1 = FormComponent.builder().value("test").build();
formComponent1.setChildren(null);
formComponent1.setParent(null);
FormComponentJoin formComponentJoin1 = FormComponentJoin.builder().pos(1).formComponent(formComponent1).build();
Form form = Form.builder().name("test").build()).child(formComponentJoin1).build();
formComponentJoin1.setForm(form);
form = formRepository.save(form);
}
这是完整的堆栈跟踪:
原因:org.hibernate.TransientPropertyValueException:对象引用未保存的瞬态实例 - 在刷新前保存瞬态实例:org.fao.backend.entity.FormComponentJoin.formComponent -> org.fao.backend.entity.FormComponent
在 org.hibernate.engine.spi.CascadingActions$8.noCascade(CascadingActions.java:398)
在 org.hibernate.engine.internal.Cascade.cascade(Cascade.java:129)
在 org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:442)
在 org.hibernate.event.internal.DefaultPersistEventListener.justCascade(DefaultPersistEventListener.java:188)
在 org.hibernate.event.internal.DefaultPersistEventListener.entityIsPersistent(DefaultPersistEventListener.java:181)
在 org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:145)
在 org.hibernate.internal.SessionImpl.firePersistOnFlush(SessionImpl.java:838)
在 org.hibernate.internal.SessionImpl.persistOnFlush(SessionImpl.java:831)
在 org.hibernate.engine.spi.CascadingActions$8.cascade(CascadingActions.java:357)
在 org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:350)
在org.hibernate.engine.internal.Cascade.cascade协会(Cascade.java:293)
在 org.hibernate.engine.internal.Cascade.cascade属性(Cascade.java:161)
在 org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:379)
在 org.hibernate.engine.internal.Cascade.cascade 集合(Cascade.java:319)
在org.hibernate.engine.internal.Cascade.cascade协会(Cascade.java:296)
在 org.hibernate.engine.internal.Cascade.cascade属性(Cascade.java:161)
在 org.hibernate.engine.internal.Cascade.cascade(Cascade.java:118)
在 org.hibernate.event.internal.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:167)
在 org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:158)
在 org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:91)
在 org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:55)
在 org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1258)
在 org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:425)
在 org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
在 org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:177)
在 org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:77)
... 省略了 58 个常见帧
最后我明白错误是在 FormComponentJoin 实体中的映射。
这是新映射:
@ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE })
@JoinColumn(name = "form_id") // , referencedColumnName = "id"
@NotFound(action = NotFoundAction.IGNORE)
@JsonIgnore
private Form form;
@ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE })
@JoinColumn(name = "form_component_id") // , referencedColumnName = "id"
@NotFound(action = NotFoundAction.IGNORE)
private FormComponent formComponent;
我就是这种情况。我有三个实体:Form、FormComponent 和 FormComponentJoin。 它是与额外列的多对多关系。 我想通过一次调用 FormRepository save() 方法来保存一个表单实体及其所有子实体,但它不起作用。 这是错误消息: 错误由以下原因引起:org.hibernate.TransientPropertyValueException:对象引用未保存的瞬态实例 - 在刷新之前保存瞬态实例 这些是我的实体:
@Data
@Entity
@Table(name = "form")
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class Form implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid")
private String id;
private String name;
@OneToMany(mappedBy = "form", cascade = { CascadeType.PERSIST, CascadeType.MERGE }, orphanRemoval = true)
@NotFound(action = NotFoundAction.IGNORE)
@Singular
private List<FormComponentJoin> formComponentJoin = new ArrayList<>();
}
@Data
@EqualsAndHashCode
@Entity
@Table(name = "form_component")
@AllArgsConstructor(suppressConstructorProperties = true)
@NoArgsConstructor
public class FormComponent implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid")
private String id;
@JsonIgnore
@OneToMany(mappedBy = "formComponent", cascade = CascadeType.ALL, orphanRemoval = true)
@NotFound(action = NotFoundAction.IGNORE)
private List<FormComponentJoin> formComponentJoin = new ArrayList<>();
@ManyToOne
@JsonIgnore
private FormComponent parent;
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
@Singular
private List<FormComponent> children;
private String value;
}
@Entity
@Table(name = "form_component_join")
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class FormComponentJoin implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid")
private String id;
@ManyToOne
@JoinColumn(name = "form_id", referencedColumnName = "id")
@NotFound(action = NotFoundAction.IGNORE)
@JsonIgnore
private Form form;
@ManyToOne
@JoinColumn(name = "form_component_id", referencedColumnName = "id")
@NotFound(action = NotFoundAction.IGNORE)
private FormComponent formComponent;
@Column(name = "position")
private int pos;
}
@Repository
@Transactional(readOnly = true)
public interface FormRepository extends PagingAndSortingRepository<Form, String> {
}
为了进行测试,我使用了 CommandLineRunner:
@Bean
public CommandLineRunner initDatabase(FormRepository formRepository) {
return (args) -> {
FormComponent formComponent1 = FormComponent.builder().value("test").build();
formComponent1.setChildren(null);
formComponent1.setParent(null);
FormComponentJoin formComponentJoin1 = FormComponentJoin.builder().pos(1).formComponent(formComponent1).build();
Form form = Form.builder().name("test").build()).child(formComponentJoin1).build();
formComponentJoin1.setForm(form);
form = formRepository.save(form);
}
这是完整的堆栈跟踪:
原因:org.hibernate.TransientPropertyValueException:对象引用未保存的瞬态实例 - 在刷新前保存瞬态实例:org.fao.backend.entity.FormComponentJoin.formComponent -> org.fao.backend.entity.FormComponent 在 org.hibernate.engine.spi.CascadingActions$8.noCascade(CascadingActions.java:398) 在 org.hibernate.engine.internal.Cascade.cascade(Cascade.java:129) 在 org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:442) 在 org.hibernate.event.internal.DefaultPersistEventListener.justCascade(DefaultPersistEventListener.java:188) 在 org.hibernate.event.internal.DefaultPersistEventListener.entityIsPersistent(DefaultPersistEventListener.java:181) 在 org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:145) 在 org.hibernate.internal.SessionImpl.firePersistOnFlush(SessionImpl.java:838) 在 org.hibernate.internal.SessionImpl.persistOnFlush(SessionImpl.java:831) 在 org.hibernate.engine.spi.CascadingActions$8.cascade(CascadingActions.java:357) 在 org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:350) 在org.hibernate.engine.internal.Cascade.cascade协会(Cascade.java:293) 在 org.hibernate.engine.internal.Cascade.cascade属性(Cascade.java:161) 在 org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:379) 在 org.hibernate.engine.internal.Cascade.cascade 集合(Cascade.java:319) 在org.hibernate.engine.internal.Cascade.cascade协会(Cascade.java:296) 在 org.hibernate.engine.internal.Cascade.cascade属性(Cascade.java:161) 在 org.hibernate.engine.internal.Cascade.cascade(Cascade.java:118) 在 org.hibernate.event.internal.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:167) 在 org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:158) 在 org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:91) 在 org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:55) 在 org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1258) 在 org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:425) 在 org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101) 在 org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:177) 在 org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:77) ... 省略了 58 个常见帧
最后我明白错误是在 FormComponentJoin 实体中的映射。
这是新映射:
@ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE })
@JoinColumn(name = "form_id") // , referencedColumnName = "id"
@NotFound(action = NotFoundAction.IGNORE)
@JsonIgnore
private Form form;
@ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE })
@JoinColumn(name = "form_component_id") // , referencedColumnName = "id"
@NotFound(action = NotFoundAction.IGNORE)
private FormComponent formComponent;