我是Hibernate的新手。我正在使用Hibernate 4.0,特别是JPA注释。
我有一个Order类。订单可以包含多个Skus('sku'是库存单位 - 请参阅Wikipedia)以及每个sku中的一个或多个。 Order和Sku课程如下。我想将订单与其关联的skus一起保存在同一个表中,但如果需要,我可以使用两个表。我无法弄清楚如何持久化HashMap - 运行时异常抛出状态javax.persistence.PersistenceException: org.hibernate.exception.DataException: Data truncation: Data too long for column 'skusInOrder' at row 1
。
我已阅读[this] [2] Stackoverflow问题: - 在我的场景中,使用@Lob注释的建议是否有意义?我是否需要使用@Embedded或@Embeddable和/或@ElementCollection?
package com.newco.drinks.data;
import java.io.Serializable;
import java.math.RoundingMode;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.MapKey;
import javax.persistence.OneToMany;
import javax.persistence.SecondaryTable;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
@Entity
@Table(name="Orders")
public class Order implements Serializable {
private static final long serialVersionUID = 5915005362337363656L;
private List<Sku> availableSkus;
private String barId;
private java.util.Date collectionNotificationTime;
private CurrencyUnit currencyUnit;
private String customerId;
private String orderId;
private Money orderTotal;
private String paymentProcessorRef;
private Boolean paymentSuccessful;
private HashMap<Sku, Integer> skusInOrder = new HashMap<Sku, Integer>(); // skuId and quantity thereof
private java.util.Date timeReceived;
/**
*
* @param sku
* @param quantity
* @throws IllegalArgumentException
* if quantity is zero or negative, or if the Order does not
* contain the Sku
* @throws ConcurrentModificationException
*/
void add(Sku sku, int quantity) throws IllegalArgumentException, ConcurrentModificationException {
if (quantity <= 0) {
throw new IllegalArgumentException("Quantity must be greater than zero, but was " + quantity);
}
if (skusInOrder.isEmpty() || !skusInOrder.containsKey(sku)) {
skusInOrder.put(sku, quantity);
} else {
if (skusInOrder.containsKey(sku)) {
int i = skusInOrder.get(sku);
skusInOrder.put(sku, i + quantity);
} else {
throw new IllegalArgumentException("Order " + getOrderId() + " does not contain SKU " + sku.getSkuId());
}
}
}
private Money calculateOrderTotal() {
int decimalPlaces = currencyUnit.getDecimalPlaces();
String zeroString = null;
switch (decimalPlaces) {
case 1:
zeroString = "0.0";
break;
case 2:
zeroString = "0.00";
break;
case 3:
zeroString = "0.000";
break;
case 4:
zeroString = "0.0000";
break;
}
Money total = Money.of(currencyUnit, new Double(zeroString));
for (Sku sku : skusInOrder.keySet()) {
int quantity = skusInOrder.get(sku);
Money totalExTax = sku.getPrice().multipliedBy(quantity, RoundingMode.HALF_UP);
double taxRate = sku.getTaxRate();
if (taxRate > 0) {
Money tax = totalExTax.multipliedBy(taxRate / 100, RoundingMode.HALF_UP);
total = total.plus(totalExTax.plus(tax));
} else {
total = total.plus(totalExTax);
}
}
return total;
}
/**
*
* @return a List of Sku objects available to be added to this order.
* Different bars will have different Skus available.
*/
@Transient
@OneToMany
public List<Sku> getAvailableSkus() {
return availableSkus;
}
@Column(name="barid", nullable=false)
public String getBarId() {
return barId;
}
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "collectionnotificationtime")
public java.util.Date getCollectionNotificationTime() {
return collectionNotificationTime;
}
@Column(name="currencyunit", nullable=false)
public CurrencyUnit getCurrencyUnit() {
return currencyUnit;
}
@Column(name="customerid", nullable=false)
public String getCustomerId() {
return customerId;
}
@Id
@Column(name="orderid", nullable=false)
public String getOrderId() {
return orderId;
}
//@Column(name="ordertotal", nullable=false)
@Transient
public Money getOrderTotal() {
return calculateOrderTotal();
}
@Column(name="paymentprocessorref", nullable=true)
public String getPaymentProcessorRef() {
return paymentProcessorRef;
}
@Column(name="paymentsuccess", nullable=true)
public Boolean getPaymentSuccessful() {
return paymentSuccessful;
}
@Column(name="skusinorder", nullable=false)
public HashMap<Sku, Integer> getSkusInOrder() {
return skusInOrder;
}
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "timereceived")
public java.util.Date getTimeReceived() {
return timeReceived;
}
/**
*
* @param sku
* @param quantity
* @throws IllegalArgumentException
* if quantity is zero or negative, or if the Sku does not form
* part of the Order
* @throws ConcurrentModificationException
*/
void remove(Sku sku, int quantity) throws IllegalArgumentException, ConcurrentModificationException {
if (quantity <= 0) {
throw new IllegalArgumentException("Quantity to remove must be greater than zero for order " + getOrderId() + ", but was " + quantity);
}
if (skusInOrder.isEmpty() || !skusInOrder.containsKey(sku)) {
throw new IllegalArgumentException("Cannot remove sku " + sku.getSkuId() + " which doesn't form part of order " + getOrderId());
} else {
int i = skusInOrder.get(sku);
if (quantity <= i) { // fine, this is expected
skusInOrder.put(sku, i - quantity);
} else if (quantity == i) { //okay, remove that sku altogether as its quantity is now zero
skusInOrder.remove(sku);
}
}
}
void setAvailableSkus(List<Sku> availableSkus) {
this.availableSkus = availableSkus;
}
void setBarId(String barId) {
this.barId = barId;
}
void setCollectionNotificationTime(
java.util.Date collectionNotificationTime) {
this.collectionNotificationTime = collectionNotificationTime;
}
void setCollectionReadySent(java.util.Date collectionReadySent) {
this.collectionNotificationTime = collectionReadySent;
}
void setCurrencyUnit(CurrencyUnit currencyUnit) {
this.currencyUnit = currencyUnit;
}
void setCustomerId(String customerId) {
this.customerId = customerId;
}
void setOrderId(String orderId) {
this.orderId = orderId;
}
void setOrderTotal(){
orderTotal = calculateOrderTotal();
}
void setPaymentProcessorRef(String paymentProcessorRef) {
this.paymentProcessorRef = paymentProcessorRef;
}
void setPaymentSuccessful(Boolean paymentSuccessful) {
this.paymentSuccessful = paymentSuccessful;
}
}
package com.newco.drinks.data;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
@Entity
@Table( name = "Skus" )
public class Sku implements Serializable{
private static final long serialVersionUID = 8375466982619713795L;
private String skuId;
private String barId;
private CurrencyUnit currencyUnit;
private double price;
private String description;
private String brand;
private String skuType;
private double taxRate;
protected Sku(){
// no args constructor for Hibernate use
}
public Sku(String skuId, String barId, CurrencyUnit currencyUnit, double price, String description, String brand, String skuType, double tax) {
setSkuId(skuId);
setBarId(barId);
setCurrencyUnit(currencyUnit);
setPrice(price);
setDescription(description);
setBrand(brand);
setSkuType(skuType);
setTaxRate(tax);
}
@Column(name="barid", nullable=false)
public String getBarId() {
return barId;
}
@Column(name="brand", nullable=true)
public String getBrand() {
return brand;
}
@Column(name="currencyunit", nullable=false)
public CurrencyUnit getCurrencyUnit() {
return currencyUnit;
}
@Column(name="description", nullable=false)
public String getDescription() {
return description;
}
@Column(name="price", nullable=false)
public Money getPrice() {
return Money.of(currencyUnit, price);
}
@Id
@Column(name="skuid", nullable=false)
public String getSkuId() {
return skuId;
}
@Column(name="skutype", nullable=false)
public String getSkuType() {
return skuType;
}
@Column(name="taxrate", nullable=false)
public double getTaxRate() {
return taxRate;
}
void setBarId(String barId) {
this.barId = barId;
}
void setBrand(String brand) {
this.brand = brand;
}
void setCurrencyUnit(CurrencyUnit currencyUnit) {
this.currencyUnit = currencyUnit;
}
void setDescription(String description) {
this.description = description;
}
void setPrice(double price) {
this.price = price;
}
void setSkuId(String skuId) {
this.skuId = skuId;
}
void setSkuType(String skuType) {
this.skuType = skuType;
}
void setTaxRate(double tax) {
this.taxRate = tax;
}
}
答案 0 :(得分:2)
首先,将您的字段定义为类型Map
而不是HashMap
(总是更喜欢用于引用对象的具体类的接口)。
然后最好的选择是使用@ElementCollection
。这样hibernate将创建一个单独的表(如果启用了hbm2ddl)并在那里填充结果。如果你使用@Lob
它仍然可以工作,但是当在java之外读取时,该字段将是一个“黑盒子”(即命令行mysql工具)