我想創建一個帶有類別的新產品。如果該類別不存在,則還要創建該類別。到目前為止,這個用例很好。
我的第二個用例是當我想創建另一個具有相同類別的產品時。由于我的 Category 物體具有唯一名稱,因此當我呼叫我的服務時,它會拋出重復的錯誤鍵。我想要的是能夠創建第二個產品并更新類別以擁有該產品。
這是我的類別物體
package com.smolano.cupboard.entities;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import javax.persistence.*;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
@Entity
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Category implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true)
private String name;
@ManyToMany(mappedBy = "categories", fetch = FetchType.LAZY)
private Set<Product> products = new HashSet<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Product> getProducts() {
return products;
}
public void setProducts(Set<Product> products) {
this.products = products;
}
}
這是我的產品物體
package com.smolano.cupboard.entities;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import javax.persistence.*;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
@Entity
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Product implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinTable(
name = "product_categories",
joinColumns = {@JoinColumn(name = "product_id")},
inverseJoinColumns = {@JoinColumn(name = "category_id")}
)
private Set<Category> categories = new HashSet<>();
private String barCode;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Category> getCategories() {
return categories;
}
public void setCategories(Set<Category> categories) {
this.categories = categories;
}
public String getBarCode() {
return barCode;
}
public void setBarCode(String barCode) {
this.barCode = barCode;
}
}
我的類別存盤庫
package com.smolano.cupboard.repositories;
import com.smolano.cupboard.entities.Category;
import org.springframework.data.jpa.repository.JpaRepository;
public interface CategoryRepository extends JpaRepository<Category, Long> {
}
和我的產品存盤庫
package com.smolano.cupboard.repositories;
import com.smolano.cupboard.entities.Product;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ProductRepository extends JpaRepository<Product, Long> {
}
我的其余代碼可以在這里找到 https://github.com/santfirax/backend-product-store-java
uj5u.com熱心網友回復:
在這個例子中,我沒有看到多對多關系的必要性。一對多可以達到目的,其中一個類別可以有多個產品,您可以使用名稱唯一的同一類別創建多個產品。
如果你仍然想實作它,你需要有一個新表,其中包含兩個表的主鍵的組合,這將是唯一的組合。請參閱這些頁面以獲取更多資訊1和2的視覺表示。
uj5u.com熱心網友回復:
盡量避免使用CascadeType.REMOVE多對多關聯,因為它可能會生成過多的查詢并洗掉比預期更多的記錄。這是一篇詳細解釋這種行為的文章。由于您CascadeType.ALL在映射中使用它,因此它也包括CascadeType.REMOVE.
關于向產品物體添加/更新新類別。重寫equals和hashCode方法會很有幫助。由于在您的示例中Category.name應該是唯一的,并且基本上您可以通過名稱區分類別,因此您的實作可能如下所示:
@Override
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Category))
return false;
Category other = (Category) o;
return (this.name == null && other.name == null) || (this.name != null && this.name.equals(other.name));
}
@Override
public int hashCode() {
return this.name.hashCode();
}
這樣您就可以確保您的Product.categories欄位不會包含同名的類別。
假設您的物體映射具有cascade = {CascadeType.PERSIST, CascadeType.MERGE},您的服務類可能類似于以下內容:
@Service
@Transactional
public class ProductService {
@Autowired
private ProductRepository productRepository;
public Product createProduct(Product product) {
return productRepository.save(product);
}
public Product saveCategoryInProduct(Long productId, Category category) {
return productRepository
.findById(productId)
.map(product -> addCategory(product, category))
.map(productRepository::save)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
}
private Product addCategory(Product product, Category category) {
product.getCategories().add(category);
return product;
}
}
通過呼叫saveCategoryInProduct,您將為產品物體添加新類別。如果類別物體包含id(非空),則將在product_categories 表中創建新記錄。
但是,如果Category物體沒有id(為空),那么將首先嘗試在category表中創建新記錄,然后將其關聯到提供的產品id(通過在 中創建記錄product_categories)。在這種情況下,您可能會遇到DuplicateKeyException. 要處理它,您可以通過addCategory以下方式修改方法:
private Product addCategory(Product product, Category category) {
product.getCategories().add(
categoryRepository
.findByName(category)
.orElse(category));
return product;
}
通過這種方式,您將確保您添加的類別是從 db 中檢索到的(因此不會再次創建)或尚不存在。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/343526.html
