我们正在使用eclipselink来保存我们的实体。在多种情况下,我们订购了包含一个实体子项的列表。当一个实体从其中一个列表移动到另一个列表时,我们经常会遇到其中一个列表中的无效订单问题(我们正在移动的列表中的空白或目标列表中的重复)。
父实体看起来像这样(我删除了大概不相关的属性,方法和注释):
@Entity
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Document implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
@OrderColumn
@JoinColumn(name = "document_id")
private List<Row> rows = new ArrayList<>();
}
此案例的子实体:
@Entity
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Row implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
}
要使用此代码移动我们开始的实体:
document.getRows().add(rowIndex, row);
documentRepository.save(document);
出现问题时,我们首先添加了代码以从旧文档中删除行:
if (oldDocument != null && !oldDocument.equals(document)) {
oldDocument.getRows().remove(row);
documentRepository.save(oldDocument);
}
有一段时间,它还有助于更改代码以将文档从save
保存到saveAndFlush
(不确定为什么会出现这种情况)。然而,这似乎不再有用了。
这些更改导致当前代码:
document.getRows().add(rowIndex, row);
documentRepository.saveAndFlush(document);
if (oldDocument != null && !oldDocument.equals(document)) {
oldDocument.getRows().remove(row);
documentRepository.saveAndFlush(oldDocument);
}
在执行任何操作之前,数据库中的行如下所示:
id document_id rows_order
113940 113306 0
114041 113306 1
114044 113306 2
115671 115129 0
115674 115129 1
将行114041移动到文档115129后,这是结果数据:
id document_id rows_order
113940 113306 0
114044 113306 2
115671 115129 0
114041 115129 1
115674 115129 2
rows_order中的差距已经显得可疑,并且在文档末尾插入新行时会出现问题:
@Transactional
public void addRow() {
Document document = documentRepository.getOne(113306);
Row newRow = new Row();
rowRepository.save(newRow);
document.getRows().add(2, newRow);
documentRepository.saveAndFlush(document);
}
这是提交事务时出现的错误消息:
Internal Exception: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "unique_document_id_rows_order"
Detail: Key (document_id, rows_order)=(113306, 2) already exists.
Error Code: 0
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:526)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:485)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:291)
at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96c(AbstractTransactionAspect.aj:70)
at com.dbcentral.service.DocumentService.addRow(DocumentService.java:100)
document.getRows()
是一个包含两个元素的列表,因此在末尾添加一个元素应该可以在索引2处添加它。
我们可以通过删除document_id和rows_order的约束来避免该错误,但这会导致重复的rows_order条目,如下所示:
id document_id rows_order
113940 113306 0
114044 113306 2
115676 113306 2
115671 115129 0
114041 115129 1
115674 115129 2
由于评论中的想法,我们尝试将@ChangeTracking
注释添加到Document实体。然而,这两项政策似乎都没有改变任何内容。
我们目前正在以正确的方式在有序列表之间移动实体,还是我们可能遗漏了什么?
另一个想法是在每次移动后运行一个sql,更正order列。关于这一点,我们不确定在应用程序运行时是否操作该列是个好主意。