我有以下课程:
分类
@Entity
@Table(name = "category", schema = "customer")
public class Category extends CustomerOwned {
...
}
CatalogueItem
@Entity
@Table(name = "catalogue_item", schema = "customer")
@EntityListeners(value = { CatalogueItemStatusListener.class })
public class CatalogueItem extends CatalogueOwned implements Statusable<CatalogueItem, CatalogueItemStatus> {
...
@OneToMany(mappedBy = "catalogueItem", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<CatalogueItemCategory> categories;
...
}
CatalogueItemCategory
@Entity
@Table(name = "catalogue_item_category", schema = "customer")
public class CatalogueItemCategory extends CatalogueItemOwned implements CategoryOwner {
...
@ManyToOne
@JoinColumn(name = "category_id", nullable = false, insertable = true, updatable = false)
private Category category;
...
}
我们在应用程序中执行的删除次数非常少,但类别是很难删除的。 CatalogueItemCategory 也被硬删除。
我正在创建一项服务,允许某人删除一个类别,同时检查所有类别依赖项并删除它们,所以我这样做:
@Transactional
public DependentItemsResultResource delete(String categoryId, boolean force) {
List<CatalogueItem> catalogueItems = catalogueItemRepository.getByCategory(getCustomerStringId(), categoryId);
DependentItemsResultResource resultResource = new DependentItemsResultResource();
resultResource.setDependentCatalogueItems(new SearchResponse().from(catalogueItems, CatalogueItemSummaryResource::new));
if (!catalogueItems.isEmpty()) {
if (!force) {
resultResource.setDeleted(false);
return resultResource;
}
catalogueItems.forEach(item -> {
item.getCategories().removeIf(catalogueItemCategory -> categoryId.equals(catalogueItemCategory.getCategory().getStringId()));
sendEvent(prepareEvent(new CatalogueItemUpdatedEvent(), item.getCatalogue().getStringId(), item.getStringId()));
});
}
Category category = getCategory(categoryId);
resultResource.setDeleted(true);
categoryRepository.delete(category);
CategoryDeletedEvent event = new CategoryDeletedEvent();
event.setCategoryPath(category.getPath());
sendEvent(prepareEvent(event, categoryId));
return resultResource;
}
这导致以下异常:
Caused by: org.h2.jdbc.JdbcSQLException: Referential integrity constraint violation: "FKLYKUEHJG9UL0LR36O5XDD3MLF: CUSTOMER.CATALOGUE_ITEM_CATEGORY FOREIGN KEY(CATEGORY_ID) REFERENCES CUSTOMER.CATEGORY(ID) (1)"; SQL statement:
delete from customer.category where id=? [23503-192]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
at org.h2.message.DbException.get(DbException.java:179)
at org.h2.message.DbException.get(DbException.java:155)
at org.h2.constraint.ConstraintReferential.checkRow(ConstraintReferential.java:426)
at org.h2.constraint.ConstraintReferential.checkRowRefTable(ConstraintReferential.java:443)
at org.h2.constraint.ConstraintReferential.checkRow(ConstraintReferential.java:318)
at org.h2.table.Table.fireConstraints(Table.java:967)
at org.h2.table.Table.fireAfterRow(Table.java:985)
at org.h2.command.dml.Delete.update(Delete.java:101)
at org.h2.command.CommandContainer.update(CommandContainer.java:98)
at org.h2.command.Command.executeUpdate(Command.java:258)
at org.h2.jdbc.JdbcPreparedStatement.executeUpdateInternal(JdbcPreparedStatement.java:160)
at org.h2.jdbc.JdbcPreparedStatement.executeUpdate(JdbcPreparedStatement.java:146)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:204)
... 109 common frames omitted
我试过更换这一位:
item.getCategories().removeIf(catalogueItemCategory -> categoryId.equals(catalogueItemCategory.getCategory().getStringId()));
用这个:
item.getCategories().stream()
.filter(catalogueItemCategory -> categoryId.equals(catalogueItemCategory.getCategory().getStringId()))
.forEach(catalogueItemCategoryRepository::delete);
但它没有任何区别。 Hibernate正在不按顺序删除对象。应该在类别对象之前删除CatalogueItemCategory对象,但事实并非如此。
如何以正确的顺序删除它?
编辑:错过了这个提供CatalogueItemCategory的父级的类:
@MappedSuperclass
public class CatalogueItemOwned extends Updateable {
...
@ManyToOne
@JoinColumn(name = "catalogue_item_id", nullable = false, insertable = true)
private CatalogueItem catalogueItem;
...
}
答案 0 :(得分:0)
有一些肮脏的解决方案,既有反模式,但也可能有效:
每次删除后使用flush
,或使用本机查询删除。
尽管如此,我建议不要使用任何这些解决方案,而是寻找更清洁的解决方案。
答案 1 :(得分:0)
我通过显式删除类别和所有依赖项来解决这个问题,如下所示:
@Transactional
public DependentItemsResultResource delete(String categoryId, boolean force) {
List<CatalogueItem> catalogueItems = catalogueItemRepository.getByCategory(getCustomerStringId(), categoryId);
DependentItemsResultResource resultResource = new DependentItemsResultResource();
resultResource.setDependentCatalogueItems(new SearchResponse().from(catalogueItems, CatalogueItemSummaryResource::new));
if (!catalogueItems.isEmpty()) {
if (!force) {
resultResource.setDeleted(false);
return resultResource;
}
catalogueItems.forEach(item -> sendEvent(prepareEvent(
new CatalogueItemUpdatedEvent(), item.getCatalogue().getStringId(), item.getStringId())));
}
Category category = getCategory(categoryId);
resultResource.setDeleted(true);
categoryRepository.deleteCatalogueItemCategoriesByCategory(category);
categoryRepository.deleteCategory(category);
CategoryDeletedEvent event = new CategoryDeletedEvent();
event.setCategoryPath(category.getPath());
sendEvent(prepareEvent(event, categoryId));
return resultResource;
}
回购方法是:
@Modifying
@Query("delete from Category c where c = :category")
void deleteCategory(@Param("category") Category category);
和
@Modifying
@Query("delete from CatalogueItemCategory where category = :category")
void deleteCatalogueItemCategoriesByCategory(@Param("category") Category category);
不是最好的,但也不是最差的。不使用本机删除,它仍在主要事务中。