Hibernate与extras列

时间:2016-01-30 18:33:56

标签: java hibernate postgresql many-to-many

我遇到了与JAVA和HIBERNATE进行多对多关系映射的问题 我购买了桌子> ------------------<产品,所以我们得到另一张桌子 purchaseProduct,这里是DDL

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


CREATE TABLE purchase (
  idPurchase      serial primary key,
  code  varchar(50) ,
  date timestamp ,
  totalHt double PRECISION,
  tva double PRECISION,
  totalTTC double PRECISION
);


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

这是我的hibernate.cfg.xml configuraiton:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

    <session-factory>

        <!-- Database connection settings -->
        <property name="connection.driver_class">org.postgresql.Driver</property>
        <property name="connection.url">jdbc:postgresql://localhost:5432/testInventory</property>
        <property name="connection.username">postgres</property>
        <property name="connection.password">myPassword</property>


        <!-- SQL dialect -->
        <property name="dialect">org.hibernate.dialect.PostgreSQL82Dialect</property>

        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>

        <mapping  class="model.Product"/>
        <mapping  class="model.Purchase"/>
        <mapping  class="model.LineCommand"/>

    </session-factory>

</hibernate-configuration>

我采用这种方法来模拟多对多的关系:

产品映射

@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> lineItems = new HashSet<LineCommand>(0);


    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(fetch = FetchType.LAZY, mappedBy = "pk.product", cascade=CascadeType.ALL)
    public Set<LineCommand> getLineItems() {
        return lineItems;
    }

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

}

购买:

@Entity
@Table(name = "purchase")
@Access(AccessType.PROPERTY)
public class Purchase {
    private LongProperty idPurchase;
    private StringProperty codePurchase;
    private ObjectProperty<Timestamp> 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")
    public Timestamp getDatePurchase() {
        return datePurchase.get();
    }

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

    public void setDatePurchase(Timestamp 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 = "pk.purchase",
            cascade = CascadeType.ALL)
    public Set<LineCommand> getLineItems() {
        return this.lineItems;
    }

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

}

purchaseProduct:

@Entity
@Table(name = "purchaseProduct")
@Access(AccessType.PROPERTY)
@AssociationOverrides({
        @AssociationOverride(name = "pk.product",
                joinColumns = @JoinColumn(name = "idProduct")),
        @AssociationOverride(name = "pk.purchase",
                joinColumns = @JoinColumn(name = "idPurchase"))})
public class LineCommand {

    // private LongProperty idProduct;
    //  private LongProperty idCommand;
    private DoubleProperty qty;
    private DoubleProperty sellPrice;
    private DoubleProperty subTotal;

    private LineCommandId compositePrimaryKey = new LineCommandId();

    @EmbeddedId
    public LineCommandId getCompositePrimaryKey() {
        return compositePrimaryKey;
    }

    public void setCompositePrimaryKey(LineCommandId compositePrimaryKey) {
        this.compositePrimaryKey = compositePrimaryKey;
    }


    private Product product;
    private Purchase purchase;

    public LineCommand() {
        // this.idProduct = new SimpleLongProperty();
        // this.idCommand = new SimpleLongProperty();
        this.qty = new SimpleDoubleProperty();
        this.sellPrice = new SimpleDoubleProperty();
        this.subTotal = new SimpleDoubleProperty();
        // Bind subtotal to qty * sellPrice
        this.subTotalProperty().bind(Bindings.multiply(this.qtyProperty(), this.sellPriceProperty()));
    }

    public LineCommand(double qty, double sellPrice) {
        //  this.idProduct.set(idProduct);
        // this.idCommand.set(idCommand);
        this.qty.set(qty);
        this.sellPrice.set(sellPrice);

        // Bind subtotal to qty * sellPrice
        this.subTotalProperty().bind(Bindings.multiply(this.qtyProperty(), this.sellPriceProperty()));
    }

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

    public DoubleProperty qtyProperty() {
        return qty;
    }

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

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

    public DoubleProperty sellPriceProperty() {
        return sellPrice;
    }

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


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

    public DoubleProperty subTotalProperty() {
        return subTotal;
    }

    @Transient
    public Product getProduct() {
        return product;
    }

    public void setProduct(Product product) {
        this.product = product;
    }

    @Transient
    public Purchase getPurchase() {
        return purchase;
    }

    public void setPurchase(Purchase purchase) {
        this.purchase = purchase;
    }
}

purchaseProduct复合键

@Embeddable
public class LineCommandId implements Serializable{
    private Product product ;
    private Purchase purchase ;

    @ManyToOne(cascade = CascadeType.ALL)
    public Product getProduct() {
        return product;
    }

    public void setProduct(Product product) {
        this.product = product;
    }

    @ManyToOne(cascade = CascadeType.ALL)
    public Purchase getPurchase() {
        return purchase;
    }

    public void setPurchase(Purchase purchase) {
        this.purchase = purchase;
    }
}

当托盘执行上述代码时,我收到此错误:

org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: model.LineCommand.pk.product in model.Product.lineItems
    at org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:769)
    at org.hibernate.cfg.annotations.CollectionBinder$1.secondPass(CollectionBinder.java:719)
    at org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:54)
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1655)
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1623)
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:278)
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.build(MetadataBuildingProcess.java:83)
    at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:418)
    at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:87)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:692)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:724)
    at util.DatabaseUtil.buildSessionFactory(DatabaseUtil.java:17)
    at util.DatabaseUtil.<clinit>(DatabaseUtil.java:11)
    at dao.DAO.<init>(DAO.java:13)
    at dao.ProductDAO.<init>(ProductDAO.java:14)
    at controller.product.productController.parentTableProperties(productController.java:79)
    at controller.product.productController.tableProperties(productController.java:74)
    at controller.product.productController.initialize(productController.java:66)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2552)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2445)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2413)
    at mains.start(mains.java:21)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$159(LauncherImpl.java:863)
    at com.sun.javafx.application.LauncherImpl$$Lambda$52/479874812.run(Unknown Source)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$172(PlatformImpl.java:326)
    at com.sun.javafx.application.PlatformImpl$$Lambda$48/704060124.run(Unknown Source)
    at com.sun.javafx.application.PlatformImpl.lambda$null$170(PlatformImpl.java:295)
    at com.sun.javafx.application.PlatformImpl$$Lambda$50/1324097194.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$171(PlatformImpl.java:294)
    at com.sun.javafx.application.PlatformImpl$$Lambda$49/1608446104.run(Unknown Source)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    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/1378653614.run(Unknown Source)
    at java.lang.Thread.run(Thread.java:745)
Exception in Application start method
Exception in thread "main" java.lang.RuntimeException: Exception in Application start method
    at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$152(LauncherImpl.java:182)
    at com.sun.javafx.application.LauncherImpl$$Lambda$2/932172204.run(Unknown Source)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.ExceptionInInitializerError
    at dao.DAO.<init>(DAO.java:13)
    at dao.ProductDAO.<init>(ProductDAO.java:14)
    at controller.product.productController.parentTableProperties(productController.java:79)
    at controller.product.productController.tableProperties(productController.java:74)
    at controller.product.productController.initialize(productController.java:66)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2552)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2445)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2413)
    at mains.start(mains.java:21)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$159(LauncherImpl.java:863)
    at com.sun.javafx.application.LauncherImpl$$Lambda$52/479874812.run(Unknown Source)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$172(PlatformImpl.java:326)
    at com.sun.javafx.application.PlatformImpl$$Lambda$48/704060124.run(Unknown Source)
    at com.sun.javafx.application.PlatformImpl.lambda$null$170(PlatformImpl.java:295)
    at com.sun.javafx.application.PlatformImpl$$Lambda$50/1324097194.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$171(PlatformImpl.java:294)
    at com.sun.javafx.application.PlatformImpl$$Lambda$49/1608446104.run(Unknown Source)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    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/1378653614.run(Unknown Source)
    ... 1 more
Caused by: java.lang.RuntimeException: There was an error building the factor
    at util.DatabaseUtil.buildSessionFactory(DatabaseUtil.java:20)
    at util.DatabaseUtil.<clinit>(DatabaseUtil.java:11)
    ... 23 more
DEBUG - Connection pool now considered primed; min-size will be maintained

1 个答案:

答案 0 :(得分:1)

mappedBy的参数应该是拥有类的字段或属性,而不是关系名称,因此您需要mappedBy = "purchase"mappedBy = "product"。事实上,对于复合键,它应该是@IdClass中映射该部分关系的属性的名称。

如果您要遵循此路径,则还应删除@EmbeddedId注释并将其替换为@IdClass - 它更清晰,更简单且符合JPA标准。

您可以移除对compositePrimaryKey的任何引用,并替换@Transient类的方法getProduct()getPurchase()上的LineCommand注释:

@Id
@ManyToOne
@JoinColumn(name = "idproduct", updatable = false, insertable = false, referencedColumnName = "idproduct")

只需修改这些方法即可使用ProductPurchase的实际实例,您需要将其添加到LineCommand类而不是compositePrimaryKey

当然,您的@Embeddable LineCommandId类应该没有注释,因为它将被用作@IdClass(请参阅下文,了解为什么使用Integer代替Long这里):

@SuppressWarnings("serial")
public class LineCommandId implements Serializable {
    private Integer product;
    private Integer purchase;
    public Integer getProduct() {
        return product;
    }
    public void setProduct(Integer idproduct) {
        this.product = idproduct;
    }
    public Integer getPurchase() {
        return purchase;
    }
    public void setPurchase(Integer idpurchase) {
        this.purchase = idpurchase;
    }
    public boolean equals(Object foo) {
        if (foo == null || foo.getClass() != this.getClass())
            return false;
        LineCommandId src = (LineCommandId)foo;
        if ((this.getProduct() == src.getProduct()) &&
            (this.getPurchase() == src.getPurchase()))
            return true;
        return false;
    }
    public int hashCode() {
        // implement
        return someHashCode;
    }
}

您需要确保的是, base 实体(例如Product)使用其LineCommandIdmappedBy字段的名称@OneToMany注释的属性。

我注意到的另一件事是您即时计算subTotal属性。由于它也不是数据库模式的一部分, 是您需要使用@Transient进行批注的属性,或者您将获得有关Hibernate为unable to find setter的异常。

NullPointerException很可能是因为你的包装器对象从null方法返回get(),比如idProduct属性,当包装器对象不是初始化:

public Long getIdProduct() {
    return idProduct.get();
}

更可能的NPE是你的一些getter方法使用自动装箱从非原语转换为原语:

public long getIdPurchase() {
    return idPurchase.get();
}

如果idPurchase.get()返回null,则自动装箱的隐式null.longValue()将导致异常。

一旦您解决了启动持久性单元的初始问题,您还会注意到Long与您在表格中使用的SERIAL根本不兼容:SERIAL映射到INTEGER,而Long映射到BIGINT。您可能想要更改它以匹配。这也是上述示例LineCommandId使用Integer s。

的原因