2017-06-06 149 views
0

我有以下类别:休眠删除已存在的无序

类别

@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; 
    ... 
} 

我们在应用程序中执行很少硬删除,但类别 s的硬删除。 CatalogueItemCategory s也被硬删除。

我创建一个服务,允许有人要删除类别,并在同一时间,我检查所有类别的依赖关系,并删除这些呢,所以我这样做:

@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

没有指定没有父子关系的OneToMany关系的CascadeType.REMOVE的行为。 – fg78nc

+0

我应该指出,我试着在List 上玩CascadeType,除了完全删除它并且没有任何帮助,并且当我这样做时,CatalogueItemCategory对象停止在列表中保持持续(在前面的“添加”操作期间) 。我尝试的第一件事是删除CascadeType.REMOVE。 – Richtopia

+0

orphanRemoval = true会隐式切换CascadeType.REMOVE – fg78nc

回答

0

有肮脏的解决方案,这都是反模式,但可能会工作:

要么使用在每次删除后使用flush,或使用本地查询删除。

也就是说,我建议不要使用这些解决方案中的任何一种,而是要寻找更干净的解决方案。

@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); 

没有最好

+0

谢谢,不幸的是我在发布问题之前尝试了这个。删除后冲洗不起作用。似乎没有做任何事情。我在删除/刷新之前和之后添加了日志记录,并且没有在它们之间的日志中打印出来。 – Richtopia

+0

请注意,我还没有使用原生查询。与此同时,我已经向Spring Boot团队报告这是一个排序错误。 – Richtopia

0

我已经明确地删除类别和所有依赖如下解决了这个,但也不是最差的。不使用本机删除,它仍在主事务中。