Its better to ask using an example so...
An entity PurchaseOrder
has a list of PurchaseOrderDetail
. OneToMany
Relation. Entity
and list items
cannot be directly saved used JPA methods as there is some calculations involved.
When we perform an update on PurchaseOrder
we have to preserve the primary key so we can update like this
PurchaseOrder purchaseOrder = purchaseOrderRepository.getOne(purchaseOrderRequest.getId());
purchaseOrder.setSupplier(purchaseOrderRequest.getSupplier());
purchaseOrder.setDollarRate(purchaseOrderRequest.getDollarRate());
purchaseOrder.setShippingCost(purchaseOrderRequest.getShippingCost());
return purchaseOrderRepository.save(purchaseOrder);
But how to Beautifully
update the List<PurchaseOrderDetail> purchaseOrderDetails
?
I have the following code which will delete existing list items and will insert new items losing the primary keys. But what is the JPA way
to do so that during update following happens
1. If some items were deleted they should be deleted from DB.
2. If some items were updated they should be updated preserving the primary keys.
3. If some new items are added they should be created having new primary keys.
Code
purchaseOrder.setPurchaseOrderDetails(null);
for (PurchaseOrderDetailRequest purchaseOrderDetailRequest : purchaseOrderRequest.getPurchaseOrderDetails())
{
PurchaseOrderDetail purchaseOrderDetail = new PurchaseOrderDetail();
purchaseOrderDetail.setPartNumber(purchaseOrderDetailRequest.getPartNumber());
purchaseOrderDetail.setDescription(purchaseOrderDetailRequest.getDescription());
purchaseOrderDetail.setQuantity(purchaseOrderDetailRequest.getQuantity());
purchaseOrderDetail.setUnitPriceInDollars(purchaseOrderDetailRequest.getUnitPriceInDollars());
purchaseOrderDetail.setTotalPriceInDollars(purchaseOrderDetailRequest.getQuantity() * purchaseOrderDetailRequest.getUnitPriceInDollars());
purchaseOrderDetail.setUnitPriceInSAR(purchaseOrder.getDollarRate() * purchaseOrderDetailRequest.getUnitPriceInDollars());
purchaseOrderDetail.setTotalPriceInSAR(purchaseOrderDetailRequest.getQuantity() * purchaseOrderDetail.getUnitPriceInSAR());
purchaseOrderDetail.setUnitCost(purchaseOrderDetail.getUnitPriceInSAR() + shippingFactor);
purchaseOrder.addPurchaseOrderDetail(purchaseOrderDetail);
}
PurchaseOrder
@Entity
@Table(name = "purchaseOrders")
public class PurchaseOrder extends UserDateAudit
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank
@Size(max = 140)
private String supplier;
@NotNull
private Float dollarRate;
@NotNull
private Float amount;
@NotNull
private Float shippingCost;
@OneToMany(
mappedBy = "purchaseOrder",
cascade = CascadeType.ALL,
fetch = FetchType.EAGER,
orphanRemoval = true
)
@Fetch(FetchMode.SELECT)
@BatchSize(size = 150)
private List<PurchaseOrderDetail> purchaseOrderDetails = new ArrayList<>();
}
PurchaseOrderDetail
@Entity
@Table(name = "purchaseOrderDetails")
public class PurchaseOrderDetail
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank
@Size(max = 50)
private String partNumber;
@Size(max = 256)
private String description;
@NotNull
private Integer quantity;
@NotNull
private Float unitPriceInDollars;
@NotNull
private Float totalPriceInDollars;
@NotNull
private Float unitPriceInSAR;
@NotNull
private Float totalPriceInSAR;
@NotNull
private Float unitCost;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "purchaseOrder_id", nullable = false)
private PurchaseOrder purchaseOrder;
}
JpaRepository.save()
doesem.persist()
orem.merge()
according to the entity state.And you also configured the mapping of the
@OneToMany
relationship withcascade = CascadeType.ALL
andorphanRemoval = true
, so you are in the right way.What you have to do in your code is updating the
PurchaseOrderDetail
elements of the List defined inPurchaseOrder
instead of creating new instances for them.You could add the existing elements in a Map to fast up the lookup processing if required.