我在 spring data jpa 中遇到了自定義洗掉方法的錯誤。基本上有一個包含物品的包,洗掉包時,應該洗掉其中的所有物品。
這是物體:
@Entity
@Table(name = "bag")
public class Bag {
@Id private Long id;
@Column("uid") private Long uid;
@Column("name") private String name;
@OneToMany(mappedBy = "bag", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Item> items;
}
@Entity
@Table(name = "item")
public class Item {
@Id private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "bid", referencedColumnName = "id")
private Bag bag;
}
和存盤庫:
@Repository
public interface BagRepository extends JpaRepository<Bag, Long> {
Bag findByUidAndName(Long uid, String name);
@Transactional
@Modifying
@Query(value = "DELETE FROM `bag` WHERE `uid` = :uid AND `name` = :name", nativeQuery = true)
void deleteByUidAndName(@Param("uid") Long uid, @Param("name") String name);
}
當我打電話時bagRepository.deleteByUidAndName(uid, name),我從休眠中得到一個與外鍵約束有關的例外。設定spring.jpa.show-sql=true顯示它不會在洗掉包之前先嘗試洗掉專案。
但是,如果我打電話Bag bag = bagRepository.findByUidAndName(uid, name),然后bagRepository.deleteById(bag.getId())一切都很好。
我想知道自定義此洗掉方法有什么問題以及如何修復它。
uj5u.com熱心網友回復:
如果通過 bagRepository.deleteById(bag.getId())Hibernate 洗掉物體將從父物體洗掉到子物體,因為您在關系上定義了cascade = CascadeType.ALL。當我們對目標物體執行某些操作時,相同的操作將應用于關聯物體。邏輯在 Hibernate 中,不使用資料庫級聯。
@OneToMany(mappedBy = "bag", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Item> items;
如果bagRepository.deleteByUidAndName(uid, name)您定義了本機查詢以進行洗掉。這意味著 Hibernate 邏輯將被忽略,查詢將按原樣執行。在這種情況下,您直接使用資料庫并通過本機 SQL 洗掉記錄,您需要ON DELETE CASCADE在資料庫級別定義以具有類似的邏輯。
@Query(value = "DELETE FROM `bag` WHERE `uid` = :uid AND `name` = :name", nativeQuery = true)
void deleteByUidAndName(@Param("uid") Long uid, @Param("name") String name);
解決方案一、@OnDelete(action = OnDeleteAction.CASCADE)
如果您有自動生成的表,您可以將特定于 Hibernate 的注釋添加@OnDelete到關系中。在表生成期間ON DELETE CASCADE將應用外鍵約束。
關系定義:
@OneToMany(mappedBy = "bag", cascade = CascadeType.ALL, orphanRemoval = true)
@OnDelete(action = OnDeleteAction.CASCADE)
private List<Item> items;
自動生成的約束:
alter table item
add constraint FK19sn210fxmx43i8r3icevbeup
foreign key (bid)
references bag
on delete cascade
實施:
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
import javax.persistence.*;
import java.util.List;
@Entity
@Table(name = "bag")
public class Bag {
@Id
private Long id;
@Column(name = "uid")
private Long uid;
@Column(name = "name")
private String name;
@OneToMany(mappedBy = "bag", cascade = CascadeType.ALL, orphanRemoval = true)
@OnDelete(action = OnDeleteAction.CASCADE)
private List<Item> items;
}
方案二、@JoinColumn注解帶外鍵 ON DELETE CASCADE
用for entity
指定外鍵ON DELETE CASCADEItem
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "bid", referencedColumnName = "id",
foreignKey = @ForeignKey(
name="FK_ITEMS_ID",
foreignKeyDefinition = "FOREIGN KEY (ID) REFERENCES ITEM(BID) ON DELETE CASCADE"))
private Bag bag;
執行:
import javax.persistence.*;
@Entity
@Table(name = "item")
public class Item {
@Id
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "bid", referencedColumnName = "id",
foreignKey = @ForeignKey(
name="FK_ITEMS_ID",
foreignKeyDefinition = "FOREIGN KEY (ID) REFERENCES ITEM(BID) ON DELETE CASCADE"))
private Bag bag;
}
解決方案 3,不要使用原生查詢
在這種情況下,將應用 Hibernate 邏輯。
定義存盤庫,如:
@Repository
public interface BagRepository extends JpaRepository<Bag, Long> {
Bag findByUidAndName(Long uid, String name);
@Transactional
@Modifying
void deleteByUidAndName(@Param("uid") Long uid, @Param("name") String name);
}
解決方案 4,手動添加 ON DELETE CASCADE 到資料庫
如果您的表不是自動生成的,您可以手動添加ON DELETE CASCADE到資料庫中。
alter table item
add constraint FK_BAG_BID
foreign key (bid)
references bag
on delete cascade
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/473255.html
