Итак, в моем весеннем приложении настроены существующие отношения ManyToMany. Похоже, что я допустил ошибку, настроив это с помощью аннотации @ManyToMany, потому что теперь мне нужно добавить поле в таблицу соединений, и это не кажется легким делом.
Моя структура - поставки и продукты. В таблице отгрузки хранится информация о том, кому была отправлена партия, в какую дату она была отправлена и т. Д. В таблице продуктов хранится информация о продукте, кто его производит, описание, размер и т. Д.
То, что я не учел при создании, было то, что мне нужно будет отслеживать количество отгруженного продукта при создании отгрузки, что должно быть сделано на соединительном столе.
Я работал с этим примером: https://vladmihalcea.com/the-best-way-to-map-a-many-to-many-association-with-extra-columns-when-using-jpa-and-hibernate/
UPDATE:
Я работал над примером выше и столкнулся с проблемой бесконечных рекурсивных вызовов между таблицами продуктов и отгрузки. Моя структура выглядит следующим образом:
ShipmentProductID.java:
// Package and Imports here
@Embeddable
public class ShipmentProductId
implements Serializable {
@Column(name = "product_id")
private Long productId;
@Column(name = "shipment_id")
private Long shipmentId;
private ShipmentProductId() {}
public ShipmentProductId(
Long productId,
Long shipmentId) {
this.productId = productId;
this.shipmentId = shipmentId;
}
// Getters and Setters here
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass())
return false;
ShipmentProductId that = (ShipmentProductId) o;
return Objects.equals(productId, that.productId) &&
Objects.equals(shipmentId, that.shipmentId);
}
@Override
public int hashCode() {
return Objects.hash(productId, shipmentId);
}
}
ShipmentProduct.java:
// Package and Imports here
@Entity(name = "ShipmentProduct")
@Table(name = "shipment_product")
public class ShipmentProduct {
@EmbeddedId
private ShipmentProductId id;
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("productId")
private Product product;
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("shipmentId")
private Shipment shipment;
@Column(name = "created_on")
private Date createdOn = new Date();
private ShipmentProduct() {}
public ShipmentProduct(Product product, Shipment shipment) {
this.product = product;
this.shipment = shipment;
this.id = new ShipmentProductId(product.getId(),
shipment.getId());
}
// Getters and Setters here
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass())
return false;
ShipmentProduct that = (ShipmentProduct) o;
return Objects.equals(product, that.product) &&
Objects.equals(shipment, that.shipment);
}
@Override
public int hashCode() {
return Objects.hash(product, shipment);
}
}
Product.java:
// Package and Imports here
@Entity
@Data
@Cache( usage = CacheConcurrencyStrategy.READ_WRITE )
public class Product extends AbstractEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@JsonIgnoreProperties("products")
// Have tried @JsonIgnore as well
@OneToMany(
mappedBy = "product",
orphanRemoval = true
)
private List<ShipmentProduct> shipments = new ArrayList<>();
@NotNull
private Integer quantity;
public boolean isAssociated(Client client){
if( this.client == null || this.client.getId() == null ||
client == null || client.getId() == null ) return
false;
return this.client.getId() == client.getId();
}
public boolean isAssociated(Expression expression){
if( this.expression == null || this.expression.getId() == null
||
expression == null || expression.getId() == null )
return false;
return this.expression.getId() == expression.getId();
}
public void addShipment(Shipment shipment) {
ShipmentProduct shipmentProduct = new ShipmentProduct(this,
shipment);
shipments.add(shipmentProduct);
shipment.getProducts().add(shipmentProduct);
}
public Set<Shipment> getAllShipments(){
Set<Shipment> shipmentList = new HashSet<>();
for (ShipmentProduct shipmentProduct : shipments) {
shipmentList.add(shipmentProduct.getShipment());
}
return shipmentList;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Product product = (Product) o;
return Objects.equals(id, product.id);
}
@Override
public String toString(){
return "";
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
Shipment.java:
// Package and Imports here
@Entity
@Data
@ToString(exclude = {"products", "contacts"})
@EqualsAndHashCode(exclude = {"products", "contacts"})
public class Shipment extends AbstractEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@JsonIgnoreProperties("shipments")
@OneToMany(
mappedBy = "shipment",
orphanRemoval = true
)
private List<ShipmentProduct> products = new ArrayList<>();
public Set<Product> getAllProducts(){
Set<Product> productList = new HashSet<>();
for (ShipmentProduct shipmentProduct : products) {
productList.add(shipmentProduct.getProduct());
}
return productList;
}
public void addProduct(Product product) {
ShipmentProduct shipmentProduct = new ShipmentProduct(product,
this);
products.add(shipmentProduct);
product.getShipments().add(shipmentProduct);
}
public void removeProduct(Product product) {
for (Iterator<ShipmentProduct> iterator = products.iterator();
iterator.hasNext(); ) {
ShipmentProduct shipmentProduct = iterator.next();
if (shipmentProduct.getShipment().equals(this) &&
shipmentProduct.getProduct().equals(product)) {
iterator.remove();
shipmentProduct.getProduct().getShipments().remove(shipmentProduct);
shipmentProduct.setShipment(null);
shipmentProduct.setProduct(null);
}
}
}
public Optional<Product> getProductById(Long productId){
Optional<ShipmentProduct> shipmentProduct =
products.stream().filter(product ->
product.getId().equals(productId)).findFirst();
return productId == null ? Optional.empty() :
Optional.of(shipmentProduct.get().getProduct());
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Shipment shipment = (Shipment) o;
return Objects.equals(id, shipment.id);
}
@Override
public String toString(){
return "";
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
Кажется, что я подхожу близко, так как это похоже на создание бесконечно большого объекта JSON. Я пробовал все виды комбинаций EAGER против LAZY и JsonIgnore и JsonIgnoreProperties. Есть мысли о том, как решить эту проблему? Мое лучшее предположение - какое-то взаимодействие с Ломбоком, но я не смог понять это.