2017-06-06 82 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

我已經明確地刪除類別和所有依賴如下解決了這個,但也不是最差的。不使用本機刪除,它仍在主事務中。