JPA / Hibernate - 将密钥映射为实体,将值映射为集合

时间:2012-11-20 20:16:09

标签: hibernate jpa

我有以下课程:

@Entity
@Table(name="ripa_request")
public class ReturningInvoiceRequest implements EntityKey<Long> {

public enum ReturningInvoiceRequestStatus {
    /**
     * This status means that the products for this request are chosen, but not confirmed at all. 
     */
    WAITING_TO_SEND("Aguardando envio para o fornecedor"),

    /**
     * This status means that the returning request is done but the supplier needs to approve the chosen products. 
     */
    WAITING_FOR_ACCEPTANCE("Aguardando aprovação do fornecedor"),

    /**
     * This status means that the invoice was generated with the returning request products and the products are dispatched.
     */
    INVOICE_DISPATCHED("Nota Fiscal de devolução emitida"), 

    /**
     * This status means that something wrong happened on the returning request process. 
     */
    INVALID("Requisição inválida");

    private String message;

    private ReturningInvoiceRequestStatus(String message) {
        this.message = message;
    }

    /* (non-Javadoc)
     * @see java.lang.Enum#toString()
     */
    @Override
    public String toString() {
        return message;
    }
}

@Id
@GeneratedValue
private Long id;

/**
 * Mapping for the Products associated to this request with related information: Product Invoice's included with chosen count.
 */
@ElementCollection(targetClass=ProductRequestContext.class)
@MapKeyJoinColumn(name="product_id")
@CollectionTable(name="ripa_request_product", joinColumns=@JoinColumn(name="request_id"))
@Columns(columns={@Column(name="invoice_id"), @Column(name="count")})
private Map<Product, Collection<ProductRequestContext>> productCountMap;

@Temporal(TemporalType.TIMESTAMP)
private Date date;

@Enumerated(EnumType.STRING)
private ReturningInvoiceRequestStatus status;


public ReturningInvoiceRequest() {
    this.status = ReturningInvoiceRequestStatus.WAITING_TO_SEND;
}

public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}    

public Collection<Product> getProductList() {
    return this.productCountMap == null ? new ArrayList<Product>() : this.productCountMap.keySet();
}

public void setProductList(Collection<Product> productList) {
    this.productCountMap = new HashMap<>();
    for (Product product : productList) {
        if (product.getInvoiceList() == null || product.getInvoiceList().isEmpty()) {
            setStatus(ReturningInvoiceRequestStatus.INVALID);
            break;
        } else {
            List<ProductRequestContext> productContextList = new ArrayList<>();
            for (Invoice invoice : product.getInvoiceList()) {
                productContextList.add(new ProductRequestContext(invoice.getId(), product.getCount(invoice)));
            }
            this.productCountMap.put(product, productContextList);  
        }
    }
}

public Date getDate() {
    return date;
}

public void setDate(Date date) {
    this.date = date;
}

public ReturningInvoiceRequestStatus getStatus() {
    return status;
}

public void setStatus(ReturningInvoiceRequestStatus status) {
    this.status = status;
}

/**
 * Return the Invoice associated to the informed Product of this request
 * @param product Product business entity
 * @return <code>Invoice</code> Invoice business entity
 */
public Invoice getInvoice(Product product) {
    for (Product requestProduct : getProductList()) {
        if (product.equals(requestProduct)) {
            Collection<ProductRequestContext> contextList = (Collection<ProductRequestContext>) this.productCountMap.get(requestProduct);
            for (ProductRequestContext context : contextList) {
                Long invoiceID = context.getRequestInvoiceID();
                for (Invoice reqInvoice : requestProduct.getInvoiceList()) {
                    if (invoiceID.equals(reqInvoice.getId())) {
                        return reqInvoice;
                    }
                }
            }
        }
    }
    return null;
}

/**
 * Return the quantity of the informed Product selected for this request.
 * @param product Product business entity
 * @return
 */
public Integer getCount(Product product) {
    for (Product requestProduct : getProductList()) {
        if (product.equals(requestProduct)) {
            Collection<ProductRequestContext> contextList = (Collection<ProductRequestContext>) this.productCountMap.get(requestProduct);
            for (ProductRequestContext context : contextList) {
                Long invoiceID = context.getRequestInvoiceID();
                for (Invoice reqInvoice : requestProduct.getInvoiceList()) {
                    if (invoiceID.equals(reqInvoice.getId())) {
                        return context.getRequestCount();
                    }
                }
            }
        }
    }
    return null;
}    


/* (non-Javadoc)
 * @see br.com.mls.eanf.entity.ifc.EntityKey#getKey()
 */
public Long getKey() {
    return id;
}

/* (non-Javadoc)
 * @see java.lang.Object#hashCode()
 */
@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((id == null) ? 0 : id.hashCode());
    return result;
}

/* (non-Javadoc)
 * @see java.lang.Object#equals(java.lang.Object)
 */
@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    ReturningInvoiceRequest other = (ReturningInvoiceRequest) obj;
    if (id == null) {
        if (other.id != null)
            return false;
    } else if (!id.equals(other.id))
        return false;
    return true;
}

/* (non-Javadoc)
 * @see java.lang.Object#toString()
 */
@Override
public String toString() {
    return this.id == null ? super.toString() : this.id.toString();
}



@Embeddable
public static class ProductRequestContext {
    /**
     * Sequence identifier for the Invoice registry on this context.
     */
    @Column(name="invoice_id")
    private long requestInvoiceID;

    @Column(name="count")
    private int requestCount;

    public ProductRequestContext() {
    }

    ProductRequestContext(Long invoiceID, Integer count) {
        this.requestInvoiceID = invoiceID;
        this.requestCount = count;
    }

    public Long getRequestInvoiceID() {
        return requestInvoiceID;
    }

    public void setRequestInvoiceID(Long invoiceID) {
        this.requestInvoiceID = invoiceID;
    }

    public int getRequestCount() {
        return requestCount;
    }

    public void setRequestCount(int count) {
        this.requestCount = count;
    }
}

}

在插入ReturningInvoiceRequest实体(通过EntityManager的persit方法)期间,与元素集合的映射关系出现问题:

javax.persistence.PersistenceException: org.hibernate.PropertyAccessException: could not get a field value by reflection getter of br.com.mls.ripa.domain.model.product.ReturningInvoiceRequest$ProductRequestContext.requestCount

在我的研究中,我发现了一些关于不支持hibernate for Collections对Map的值的信息,以及http://blog.xebia.com/2007/10/05/mapping-multimaps-with-hibernate/上的MultiMap方法,但我不知道它是否能解决我的问题

我还尝试使用Google Collections中的Multimap类来抑制Collection值,也不起作用,因为它没有扩展java.util.Map,这是hibernate理解的那个,而apache-collections MultiMap没有不支持Generics,这是Hibernate映射所必需的

我正在使用Hibernate 3.6.9,但在版本4.1.8上仍然会发生错误。

由于

1 个答案:

答案 0 :(得分:0)

我找到的解决方案是使用ProductRequestContext列表:

@ElementCollection
@CollectionTable(name="ripa_request_product", joinColumns=@JoinColumn(name="request_id"))
@Columns(columns={@Column(name="product_id"), @Column(name="invoice_id"), @Column(name="count")})
private List<ProductRequestContext> productCountList