Hibernate - 持久化地图

时间:2012-12-28 14:07:45

标签: hibernate jpa hashmap

我是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;
    }



}

[2]:How to persist a HashMap with hibernate,整数

1 个答案:

答案 0 :(得分:2)

首先,将您的字段定义为类型Map而不是HashMap(总是更喜欢用于引用对象的具体类的接口)。

然后最好的选择是使用@ElementCollection。这样hibernate将创建一个单独的表(如果启用了hbm2ddl)并在那里填充结果。如果你使用@Lob它仍然可以工作,但是当在java之外读取时,该字段将是一个“黑盒子”(即命令行mysql工具)