Java JPA-如何使用列表放置对象并使用CRUD更新列表对象?

时间:2019-02-24 15:50:45

标签: java spring-boot jpa spring-data-jpa crud

我有一个对象,其中包含其他我似乎无法正确更新的对象的列表。我可以用对象列表(ProductItemQuantity)创建对象(产品),没有问题。我也可以使用对象列表进行PUT,但是我所做的所有操作都会创建一个新的对象列表。我希望我提供的对象列表得到更新,而不是每次我放置父对象时都要创建一个新列表。

如果我向ProductItemQuantity添加ID,则会出现异常:

30,000

这是我的课程:

Product.java

detached entity passed to persist

ProductItemQuantity.java

    @Entity 
public class Product {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY) 
    private Long id;
    @ManyToOne
    private Organization org;
    private String barCode;
    private String name;
    @ManyToOne(cascade=CascadeType.MERGE)
    private Status status;
    @ManyToMany(cascade=CascadeType.MERGE)
    private List<Fee> fees;
    @ManyToMany(cascade=CascadeType.ALL)
    private List<Note> notes;
    @ManyToMany(cascade=CascadeType.ALL)
    private List<ProductItemQuantity> productItems;
    private Integer stock;
    private BigDecimal msrp;
    @CreationTimestamp
    private LocalDateTime createdOn;
    @UpdateTimestamp
    private LocalDateTime updatedOn;

    // Getter & Setters

ProductItem.java

@Entity 
public class ProductItemQuantity {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY) 
    private Long id;
    private Integer count;
    @ManyToOne
    private ProductItem productItem;
    @CreationTimestamp
    private LocalDateTime createdOn;
    @UpdateTimestamp
    private LocalDateTime updatedOn;

// Getters / setters

ProductController.java

@Entity 
public class ProductItem {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY) 
    private Long id;
    @ManyToOne
    private Organization org;
    @ManyToOne
    private Supplier supplier;
    private String barCode;
    private String description;
    private String name;
    private Integer stock;
    private Integer caseQty;
    private BigDecimal caseCost;
    @ManyToMany(cascade=CascadeType.ALL)
    private List<Note> notes;
    @CreationTimestamp
    private LocalDateTime createdOn;
    @UpdateTimestamp
    private LocalDateTime updatedOn;

有效的CRUD PUT请求:http://localhost:8080/product/1

@PutMapping("/{id}")
public Product update(@RequestBody Product product, @PathVariable long id) {


    Product savedProduct = productService.save(product);


    return savedProduct;
}

残破的CRUD PUT请求:http://localhost:8080/product/1

{
    "barcode":"12347163",
    "name":"Product 1",
    "stock": 12,
    "msrp": 29.99,
    "org": {
        "id":1
    },
    "status":{
        "id":1
    },
    "productItems":[{
        "count":30
    },{
        "count":30
    }
        ],
        "fees":[{
            "id":1

        },{
            "id":2

        }],
    "notes":[{
        "title":"Product Created",
        "description":"Note created by user X on 12/16/2019 11:00PM"
    },{
        "title":"Product Updated",
        "description":"Product updated stock by user X on 12/16/2019 11:00PM"
    }]
}

2 个答案:

答案 0 :(得分:1)

因为对象(OneToMany,ManyToMany)的关系仅从一个方向设置,所以您的对象已分离。为了持久化它们,您必须设置双向关系。您的关系是单向的,因为解析器(杰克逊)将创建以下对象:

Product product = new Product();
Fee fee = new Fee();
fee.setId(1);
product.setFees(Arrays.asList(fee));

在双向关系中,必须设置双方:

product.getFees().forEach(fee-> fee.getProducts().add(product));

因为将持久性对象也处理关系,所以最好将持久性对象与控制器对象分开。

根据我的经验,如果要使用GeneratedValue,首先必须从数据库中选择实体,然后再对其进行修改。如果您希望休眠生成一个新对象并在其上设置ID,则没有太大意义。

因此,您可能需要先进行选择:

列出费用= //在产品费用列表中选择所有ID为ID的费用

及之后:

product.setFees(fees);
fees.forEach(fee -> fee.getProducts().add(product));

您的方法是PUT,因此您不应直接保存产品对象(它将在数据库中创建一个新条目)。

@PutMapping("/{id}")
public Product update(@RequestBody Product product, @PathVariable long id) {
    Optional<Product> originalProductOptional = productRepository.findById(id);
    // you should add a check here : if originalProduct is not found, return 404
    Product originalProduct = originalProductOptional.get();
    originalProduct.setName(product.getName());
    // here update all fields and relations

    productRepository.save(originalProduct);
    return originalProduct;
 }

答案 1 :(得分:0)

答案是将属性更新为此:

  Future<void> init(String appId,
  {Map<OSiOSSettings, dynamic> iOSSettings}) async {
  _onesignalLog(OSLogLevel.verbose,
    "Initializing the OneSignal Flutter SDK ($sdkVersion)");

  var finalSettings = _processSettings(iOSSettings);

  await _channel.invokeMethod(
    'OneSignal#init', {'appId': appId, 'settings': finalSettings});
}

然后在推杆中手动设置

@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) 
private List<ProductItemQuantity> productItemQuantities;
相关问题