使用 JpaRepository 更新实体中的列表项(保留主键) [英] Updating List items(preserving primary keys) in an entity using JpaRepository

查看:22
本文介绍了使用 JpaRepository 更新实体中的列表项(保留主键)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最好用例子提问,这样...

Its better to ask using an example so...

实体PurchaseOrder 有一个PurchaseOrderDetail 列表.OneToMany 关系.Entitylist items 不能直接保存使用 JPA 方法,因为涉及一些计算.当我们对 PurchaseOrder 执行更新时,我们必须保留主键,以便我们可以像这样更新

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);

但是如何漂亮地更新List购买订单详情 ?

我有以下代码将删除现有列表项并插入丢失主键的新项.但是 JPA 方式 是做什么的,以便在更新过程中发生以下事件

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.

代码

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);
        }

采购订单

@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<>();
}

采购订单详情

@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()em.persist()em.merge() 根据实体状态.
并且您还配置了 @OneToMany 关系与 cascade = CascadeType.ALLorphanRemoval = true 的映射,因此您走对了.
您必须在代码中执行的是更新 PurchaseOrder 中定义的 List 的 PurchaseOrderDetail 元素,而不是为它们创建新实例.
如果需要,您可以在 Map 中添加现有元素以加快查找处理.

JpaRepository.save() does em.persist() or em.merge() according to the entity state.
And you also configured the mapping of the @OneToMany relationship with cascade = CascadeType.ALL and orphanRemoval = 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 in PurchaseOrder instead of creating new instances for them.
You could add the existing elements in a Map to fast up the lookup processing if required.

// collect existing details into a map to fast up
Map<Long, PurchaseOrderDetail> purchaseOrderDetailByIdMap = 
purchaseOrder.getPurchaseOrderDetails()
             .stream()
             .collect(toMap(PurchaseOrderDetail::getId, p -> p);

//collect new details into a list
List<PurchaseOrderDetail> updatedDetails = 
purchaseOrderRequest.getPurchaseOrderDetails()
                    .stream()
                    .map(detailReq -> mapDetailRequestToDetail(detailReq, 
                                      purchaseOrderDetailByIdMap))
                    .collect(toList());

// overwrite the relationship with the updatedDetails var
purchaseOrder.setPurchaseOrderDetails(updatedDetails);

// ...      

// mapping function extracted to be clearer
private PurchaseOrderDetail mapDetailRequestToDetail(PurchaseOrderDetailRequest purchaseOrderDetailRequest, 
                         Map<Long, PurchaseOrderDetail> purchaseOrderDetailByIdMap) {             

    // Here you get the existing element with the defined id or you create a new one            
    PurchaseOrderDetail purchaseOrderDetail = 
    purchaseOrderDetailByIdMap.computeIfAbsent(purchaseOrderDetailRequest.getId(), k-> new PurchaseOrderDetail());

    // set fields
    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);

    return purchaseOrderDetail;         
}

这篇关于使用 JpaRepository 更新实体中的列表项(保留主键)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆