我遇到了与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
答案 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")
只需修改这些方法即可使用Product
和Purchase
的实际实例,您需要将其添加到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
)使用其LineCommandId
中mappedBy
字段的名称@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。