JPA Mappings (OneToMany, ManyToOne)

87 Views Asked by At

Sale Class

@Entity
@Table(name = "sale")
@AllArgsConstructor
@NoArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
@Data
public class Sale {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    int id;
    @Column(name = "sale_price")
    BigDecimal salePrice;
    @Column(name = "sale_time")
    LocalDateTime saleTime;
    @OneToMany(mappedBy = "sale", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    List<SaleItem> saleItems;
}

SaleItem Class


@Entity
@Table(name = "sale_item")
@AllArgsConstructor
@NoArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
@Data
public class SaleItem {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    int id;
    @ManyToOne
    @JoinColumn(name = "product_id", referencedColumnName = "id")
    Product product;
    int quantity;
    BigDecimal price;
    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "sale_id", referencedColumnName = "id")
    Sale sale;
}

Deleting saleItem from sale_item table

Sale sale=repo.findById(saleId).
orElseThrow(()->new NoSuchElementException("There is no sale with the id"));
SaleItem theSaleItem=sale.getSaleItems().stream().filter
(saleItem->saleItem.getProduct().getBarcode().equals(barcode)).findFirst().get();
saleItemRepo.delete(theSaleItem);

SQL codes

Hibernate: select si1_0.id,si1_0.price,p1_0.id,p1_0.barcode,p1_0.category,p1_0.price,p1_0.name,p1_0.quantity,si1_0.quantity,s1_0.id,s1_0.sale_price,s1_0.sale_time from sale_item si1_0 left join product p1_0 on p1_0.id=si1_0.product_id left join sale s1_0 on s1_0.id=si1_0.sale_id where si1_0.id=?
Hibernate: select si1_0.sale_id,si1_0.id,si1_0.price,p1_0.id,p1_0.barcode,p1_0.category,p1_0.price,p1_0.name,p1_0.quantity,si1_0.quantity from sale_item si1_0 left join product p1_0 on p1_0.id=si1_0.product_id where si1_0.sale_id=?
Hibernate: select si1_0.id,si1_0.price,p1_0.id,p1_0.barcode,p1_0.category,p1_0.price,p1_0.name,p1_0.quantity,si1_0.quantity,s1_0.id,s1_0.sale_price,s1_0.sale_time from sale_item si1_0 left join product p1_0 on p1_0.id=si1_0.product_id left join sale s1_0 on s1_0.id=si1_0.sale_id where si1_0.id=?
Hibernate: select si1_0.sale_id,si1_0.id,si1_0.price,p1_0.id,p1_0.barcode,p1_0.category,p1_0.price,p1_0.name,p1_0.quantity,si1_0.quantity from sale_item si1_0 left join product p1_0 on p1_0.id=si1_0.product_id where si1_0.sale_id=?
Hibernate: delete from sale_item where id=?
Hibernate: delete from sale_item where id=?
Hibernate: delete from sale_item where id=?
Hibernate: delete from sale_item where id=?
Hibernate: delete from sale where id=?

I have 'sale' and 'sale_item' tables as you see Cascade types 'ALL' in mappings When I save sale it saves sale_items as I want But when I want to delete specific sale_item it deletes all saleItems which have same sale_id and related sale For example in sale table I have a sale that id = 2 and in sale_item table I have 3 saleItems that ids are 1,2,3 respectively. When I delete saleItem that id = 1, It automatically deletes all saleItems (1,2,3) and sale from 'sale' table that has id 2.

1

There are 1 best solutions below

2
Morteza Jalambadani On

The CascadeType.ALL used in the SaleItem entity implies that all operations associated with SaleItem are affected. When you use the delete operation, it results in the deletion of every SaleItem with the same sale_id.

By removing the cascade of sale in the SaleItem entity, it signifies that without specifying any cascade type, no cascading operations will be applied to the associated entities when performing operations.

you should change:

@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "sale_id", referencedColumnName = "id")
Sale sale;

to:

@ManyToOne
@JoinColumn(name = "sale_id", referencedColumnName = "id")
Sale sale;

for deleting data use this code:

Sale sale = repo.findById(saleId)
        .orElseThrow(() -> new NoSuchElementException("There is no sale with the id"));

Optional<SaleItem> optionalSaleItem = sale.getSaleItems().stream()
        .filter(saleItem -> saleItem.getProduct().getBarcode().equals(barcode))
        .findFirst();

if (optionalSaleItem.isPresent()) {
    SaleItem theSaleItem = optionalSaleItem.get();
    sale.getSaleItems().remove(theSaleItem); // Remove the saleItem from the sale
    saleItemRepo.delete(theSaleItem); // Delete the saleItem explicitly

    // Save the sale without the deleted saleItem
    repo.save(sale);
} else {
    //show log if saleItem not found
}