为什么hibernate会抛出带有@Version字段的org.hibernate.TransientPropertyValueException?

问题描述 投票:0回答:1

休眠抛出:

引起:org.hibernate.TransientPropertyValueException:对象引用未保存的瞬态实例 - 在刷新之前保存瞬态实例:api.models.SaleItem.product -> api.models.Product

但是如果我不使用版本字段和 LockModeType.OPTIMISTIC,它就可以工作

我有以下课程

@Entity
@Table(name = "products")
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    @Column(unique = true, nullable = false)
    @NotNull(message = "name is required")
    @Size(min = 3, max = 50, message = "name must be between 3 and 50 characters")
    private String name;
    @Min(value = 1, message = "price not be less than 1")
    @Max(value = 1000000, message = "price should not be greater than 1000000")
    private float price;
    @Min(value = 0, message = "stock not be less than 0")
    @Max(value = 10000, message = "stock should not be greater than 10000")
    private int stock;
    @Min(value = 1, message = "minimum stock not be less than 1")
    @Max(value = 1000, message = "minimum stock should not be greater than 1000")
    @Column(name = "minimum_stock")
    private int minimumStock;
    private Status status;
    @ImageSize
    private String image;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "category_id", nullable = false)
    @NotNull(message = "category cannot be null")
    private Category category;
    @Version
        private Integer version;

    public Product() {
        this.status = Status.ACTIVE;    
    }
    
    public Product(Integer id) {
        this.id=id;
        this.status=Status.ACTIVE;
    }

        @PrePersist
    void onCreate() {
        for (SaleItem item : items)
            item.setSale(this);
        for (Payment payment : payments)
            payment.setSale(this);
        if(this.discount!=null)
            this.discount.setSale(this);
        if(this.surcharge!=null)
            this.surcharge.setSale(this);
    }
    ...
}

@Entity
@Table(name = "sales_items")
public class SaleItem {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="product_id")
    @NotNull(message="product cannot be null")
    private Product product;
    @Min(value = 1, message = "quantity not be less than 1")
        @Max(value = 10000, message = "quantity should not be greater than 10000")
    private int quantity;
    @Min(value = 0, message = "price not be less than 1")
        @Max(value = 1000000, message = "price should not be greater than 1000000")
    private float price;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "sale_id")
    @JsonIgnore
    private Sale sale;
        ...
    
}

存储库方法:

public Sale save(Sale entity) {
        EntityManager em = emf.createEntityManager();
        try {
            em = emf.createEntityManager();
            em.getTransaction().begin();
            em.persist(entity);
            updateStock(entity.getItems(), em);
            em.getTransaction().commit();
            em.close();
            return entity;
        } catch (PersistenceException e) {
            em.getTransaction().rollback();
            e.printStackTrace();
        } finally {
            em.close();
        }
    }
private void updateStock(List<SaleItem> items, EntityManager em) {
        for (SaleItem item : items) {
            Product product = em.find(Product.class, item.getProduct().getId(),LockModeType.OPTIMISTIC);
            product.setStock(product.getStock() - item.getQuantity());
        }
    }

控制器方法:

public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        Sale sale = mapper.readValue(Util.getPayload(request), Sale.class);
        List<String> errors = validate(sale);
        if (!errors.isEmpty())
            Util.sendAsJson(response, errors, mapper);
        else {
            sale.setUser(new User(Double.valueOf(request.getAttribute("id").toString()).intValue()));
            sale.setDate(new Date());
            Util.sendAsJson(response, saleRepo.save(sale), mapper);
        }

我尝试过其他版本的休眠,但它不起作用。

hibernate jpa optimistic-concurrency
1个回答
0
投票

我认为问题在于 SaleItem 实体上的以下关系定义:

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="product_id")
@NotNull(message="product cannot be null")
private Product product;

您没有指定是否通过持久化SaleItem实体来持久化Product实体,因此您必须将cascade属性添加到@ManyToOne关系中,例如cascade = CascadeType.ALL或CascadeType.PERSIST。

© www.soinside.com 2019 - 2024. All rights reserved.