多次休眠:具有级联的集合all-delete-orphan

时间:2016-02-08 12:18:04

标签: java entity-framework hibernate postgresql

我有两个实体,购买和产品。他们有很多关系:

Purchase >-------purchaseProduct---------< Product

他们之间 我已将这些实体映射到一起。保存或删除购买时一切正常。当我执行更新时,只有父级(购买将更新)和子级(LineCommand)不会被更新(意味着从数据库中删除旧子项并插入新的子级)。

这里是购买和产品及协会的DDL:LineCommand:

购买:

CREATE TABLE purchase
    (
      idpurchase serial NOT NULL,
      code character varying(50),
      date timestamp without time zone,
      totalht double precision,
      tva double precision,
      totalttc double precision,
      CONSTRAINT purchase_pkey PRIMARY KEY (idpurchase)
    )

产品:

CREATE TABLE product (
  idProduct      serial primary key,
  nameAr         varchar(50),
  nameFr         varchar(50),
  preference       varchar(50),
  qtyStart       double PRECISION,
  qtyInHand      double PRECISION,
  sellPrice      double PRECISION ,
  purchasePrice  double PRECISION,
  taxe           double PRECISION
);

LineCommand:

CREATE TABLE purchaseProduct (
      idPurchase integer,
      idProduct integer,
      qty double PRECISION, 
      price double  PRECISION,
      primary key(idPurchase,idProduct),
      foreign key(idPurchase) references purchase(idPurchase),
      foreign key(idProduct) references product(idProduct) 
    );

上述实体的映射:

@Entity
@Table(name = "purchase")
@Access(AccessType.PROPERTY)
public class Purchase {
    private LongProperty idPurchase;
    private StringProperty codePurchase;
    private ObjectProperty<LocalDate> datePurchase;
    private DoubleProperty totalHt;
    private DoubleProperty tva;
    private DoubleProperty totalTTC;

    private Set<LineCommand> lineItems = new HashSet<LineCommand>(0);

    public Purchase() {
        this.idPurchase = new SimpleLongProperty();
        this.codePurchase = new SimpleStringProperty();
        this.datePurchase = new SimpleObjectProperty<>();
        this.totalHt = new SimpleDoubleProperty();
        this.tva = new SimpleDoubleProperty();
        this.totalTTC = new SimpleDoubleProperty();


    }

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "purchase_seq_gen")
    @SequenceGenerator(name = "purchase_seq_gen", sequenceName = "purchase_idpurchase_seq", initialValue = 1, allocationSize = 1)
    @Column(name = "idpurchase", unique = true, nullable = false)
    public long getIdPurchase() {
        return idPurchase.get();
    }

    public LongProperty idPurchaseProperty() {
        return idPurchase;
    }

    public void setIdPurchase(long idPurchase) {
        this.idPurchase.set(idPurchase);
    }

    @Column(name = "code")
    public String getCodePurchase() {
        return codePurchase.get();
    }

    public StringProperty codePurchaseProperty() {
        return codePurchase;
    }

    public void setCodePurchase(String codePurchase) {
        this.codePurchase.set(codePurchase);
    }

    @Column(name = "date")
    @Convert(converter = LocalDatePersistanceConverter.class)
    public LocalDate getDatePurchase() {
        return datePurchase.get();
    }

    public ObjectProperty<LocalDate> datePurchaseProperty() {
        return datePurchase;
    }

    public void setDatePurchase(LocalDate datePurchase) {
        this.datePurchase.set(datePurchase);
    }

    @Column(name = "totalHt")
    public double getTotalHt() {
        return totalHt.get();
    }

    public DoubleProperty totalHtProperty() {
        return totalHt;
    }

    public void setTotalHt(double totalHt) {
        this.totalHt.set(totalHt);
    }

    @Column(name = "tva")
    public double getTva() {
        return tva.get();
    }

    public DoubleProperty tvaProperty() {
        return tva;
    }

    public void setTva(double tva) {
        this.tva.set(tva);
    }

    @Column(name = "totalTTC")
    public double getTotalTTC() {
        return totalTTC.get();
    }

    public DoubleProperty totalTTCProperty() {
        return totalTTC;
    }

    public void setTotalTTC(double totalTTC) {
        this.totalTTC.set(totalTTC);
    }


    @OneToMany(mappedBy = "primaryKey.purchase", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
    @Fetch(value = FetchMode.SUBSELECT)
    public Set<LineCommand> getLineItems() {
        return this.lineItems;
    }

    public void setLineItems(Set<LineCommand> lineItems) {
        this.lineItems = lineItems;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        } else {

            if (this.idPurchase.getValue() == ((Purchase) obj).getIdPurchase())
                return true;
            else
                return false;
        }
    }

}

产品:

@Entity
@Table(name = "Product")
@Access(AccessType.PROPERTY)
public class Product {
    private LongProperty idProduct;
    private StringProperty nameAr;
    private StringProperty nameFr;
    private StringProperty preference;
    private DoubleProperty qtyStart;
    private DoubleProperty qtyInHand;
    private DoubleProperty sellPrice;
    private DoubleProperty purchasePrice;
    private DoubleProperty taxe;

    private Set<LineCommand> items = new HashSet<LineCommand>();


    public void setIdProduct(long idProduct) {
        this.idProduct.set(idProduct);
    }


    public Product() {
        idProduct = new SimpleLongProperty();
        nameAr = new SimpleStringProperty();
        nameFr = new SimpleStringProperty();
        preference = new SimpleStringProperty();
        qtyStart = new SimpleDoubleProperty();
        qtyInHand = new SimpleDoubleProperty();
        sellPrice = new SimpleDoubleProperty();
        purchasePrice = new SimpleDoubleProperty();
        taxe = new SimpleDoubleProperty();
    }

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "product_seq_gen")
    @SequenceGenerator(name = "product_seq_gen", sequenceName = "product_idproduct_seq", initialValue = 1, allocationSize = 1)
    @Column(name = "idproduct", unique = true, nullable = false)
    public Long getIdProduct() {
        return idProduct.get();
    }

    public LongProperty idProductProperty() {
        return idProduct;
    }

    public void setIdProduct(Long idProduct) {
        this.idProduct.set(idProduct);
    }

    @Column(name = "nameAr")
    public String getNameAr() {
        return nameAr.get();
    }

    public StringProperty nameArProperty() {
        return nameAr;
    }

    public void setNameAr(String nameAr) {
        this.nameAr.set(nameAr);
    }

    @Column(name = "nameFr")
    public String getNameFr() {
        return nameFr.get();
    }

    public StringProperty nameFrProperty() {
        return nameFr;
    }

    public void setNameFr(String nameFr) {
        this.nameFr.set(nameFr);
    }

    @Column(name = "preference")
    public String getPreference() {
        return preference.get();
    }

    public StringProperty preferenceProperty() {
        return preference;
    }

    public void setPreference(String preference) {
        this.preference.set(preference);
    }

    @Column(name = "qtyStart")
    public double getQtyStart() {
        return qtyStart.get();
    }

    public DoubleProperty qtyStartProperty() {
        return qtyStart;
    }

    public void setQtyStart(double qtyStart) {
        this.qtyStart.set(qtyStart);
    }

    @Column(name = "qtyInHand")
    public double getQtyInHand() {
        return qtyInHand.get();
    }

    public DoubleProperty qtyInHandProperty() {
        return qtyInHand;
    }

    public void setQtyInHand(double qtyInHand) {
        this.qtyInHand.set(qtyInHand);
    }

    @Column(name = "sellPrice")
    public double getSellPrice() {
        return sellPrice.get();
    }

    public DoubleProperty sellPriceProperty() {
        return sellPrice;
    }

    public void setSellPrice(double sellPrice) {
        this.sellPrice.set(sellPrice);
    }

    @Column(name = "purchasePrice")
    public double getPurchasePrice() {
        return purchasePrice.get();
    }

    public DoubleProperty purchasePriceProperty() {
        return purchasePrice;
    }

    public void setPurchasePrice(double purchasePrice) {
        this.purchasePrice.set(purchasePrice);
    }

    @Column(name = "taxe")
    public double getTaxe() {
        return taxe.get();
    }

    public DoubleProperty taxeProperty() {
        return taxe;
    }

    public void setTaxe(double taxe) {
        this.taxe.set(taxe);
    }

    @OneToMany(mappedBy = "primaryKey.product", cascade = CascadeType.ALL)
    public Set<LineCommand> getItems() {
        return this.items;
    }

    public void setItems(Set<LineCommand> lineItems) {
        this.items = lineItems;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        } else {

            if (this.idProduct.getValue() == ((Product) obj).getIdProduct())

                return true;
            else
                return false;
        }
    }
}

LineCommand:

@Entity
@Table(name = "purchaseProduct")
@Access(AccessType.PROPERTY)
@AssociationOverrides({
        @AssociationOverride(name = "primaryKey.product",
                joinColumns = @JoinColumn(name = "idproduct")),
        @AssociationOverride(name = "primaryKey.purchase",
                joinColumns = @JoinColumn(name = "idpurchase"))})

public class LineCommand implements Serializable {


    // Compostie key;
    private LineCommandId primaryKey = new LineCommandId();

    private DoubleProperty sellPrice = new SimpleDoubleProperty();
    private DoubleProperty qty = new SimpleDoubleProperty();
    private DoubleProperty subTotal = new SimpleDoubleProperty();


    public LineCommand() {

        this.sellPrice = new SimpleDoubleProperty();
        this.qty = new SimpleDoubleProperty();
        this.subTotal = new SimpleDoubleProperty();

        NumberBinding subTotalBinding = Bindings.multiply(this.qty, this.sellPrice);
        subTotal.bind(subTotalBinding);

    }

    @EmbeddedId
    public LineCommandId getPrimaryKey() {
        return primaryKey;
    }

    public void setPrimaryKey(LineCommandId primaryKey) {
        this.primaryKey = primaryKey;
    }

    @Transient
    public Product getProduct() {
        return primaryKey.getProduct();
    }

    public void setProduct(Product product) {
        primaryKey.setProduct(product);
    }

    @Transient
    public Purchase getPurchase() {
        return primaryKey.getPurchase();
    }

    public void setPurchase(Purchase purchase) {
        primaryKey.setPurchase(purchase);
    }


    @Column(name = "price")
    public double getSellPrice() {
        return sellPrice.get();
    }

    public DoubleProperty sellPriceProperty() {
        return sellPrice;
    }

    public void setSellPrice(double sellPrice) {
        this.sellPrice.set(sellPrice);
    }

    @Column(name = "qty")
    public double getQty() {
        return qty.get();
    }

    public DoubleProperty qtyProperty() {
        return qty;
    }

    public void setQty(double qty) {
        this.qty.set(qty);
    }

    @Transient
    public double getSubTotal() {
        return subTotal.get();
    }

    public DoubleProperty subTotalProperty() {
        return subTotal;
    }

    public void setSubTotal(double subTotal) {
        this.subTotal.set(subTotal);
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        } else {
            Product product = ((LineCommand) obj).getProduct();
           Purchase purchase = ((LineCommand) obj).getPurchase();

            if (getProduct().equals(product))
                return true;
            else
                return false;
        }
    }


}

由于保存和删除方法完美无缺,我只使用了更新方法代码。

 public boolean update(Purchase obj) {
        try {
            if (!session.isOpen())
                session = DatabaseUtil.getSessionFactory().openSession();
            session.beginTransaction();

            Purchase purchase = session.get(Purchase.class, obj.getIdPurchase());
            purchase.setCodePurchase(obj.getCodePurchase());
            purchase.setDatePurchase(obj.getDatePurchase());
            purchase.setTotalHt(obj.getTotalHt());
            purchase.setTva(obj.getTva());
            purchase.setTotalTTC(obj.getTotalTTC());

            purchase.getLineItems().clear();
            purchase.setLineItems(obj.getLineItems());

            session.getTransaction().commit();
            session.close();
            return true;

        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }

执行上述功能后,我得到一个异常:

org.hibernate.HibernateException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: model.Purchase.lineItems
    at org.hibernate.engine.internal.Collections.processDereferencedCollection(Collections.java:99)
    at org.hibernate.engine.internal.Collections.processUnreachableCollection(Collections.java:50)
    at org.hibernate.event.internal.AbstractFlushingEventListener.flushCollections(AbstractFlushingEventListener.java:243)
    at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:86)
    at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:38)
    at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1282)
    at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:465)
    at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2963)
    at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2339)
    at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:485)
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:147)
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$100(JdbcResourceLocalTransactionCoordinatorImpl.java:38)
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:231)
    at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:65)
    at dao.PurchaseDAO.update(PurchaseDAO.java:41)
    at controller.purchase.PurchaseController.btnSaveClicked(PurchaseController.java:349)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71)
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275)
    at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1767)
    at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1653)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.Node.fireEvent(Node.java:8390)
    at javafx.scene.control.Button.fire(Button.java:185)
    at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
    at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3758)
    at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3486)
    at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
    at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2495)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:350)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:275)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$350(GlassViewEventHandler.java:385)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$$Lambda$431/1622936725.get(Unknown Source)
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:404)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:384)
    at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
    at com.sun.glass.ui.View.notifyMouse(View.java:927)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$145(WinApplication.java:101)
    at com.sun.glass.ui.win.WinApplication$$Lambda$38/673617397.run(Unknown Source)
    at java.lang.Thread.run(Thread.java:745)

我希望这清楚地表明我的主要问题。

1 个答案:

答案 0 :(得分:1)

您正在Purchase上设置新的purchase.setLineItems(obj.getLineItems()) 集合实例。

替换:

purchase.getLineItems().addAll(obj.getLineItems())

使用:

{{1}}