2011-06-03 63 views
1

我有以下实体:OpenJPA的级联坚持一个一对多与@EmbeddedId

发票

@Entity 
@Table(name = "invoice") 
public class Invoice implements Serializable { 
    private static final long serialVersionUID = 1L; 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column(name = "InvoiceID") 
    private Long invoiceID; 

    @Basic(optional = false) 
    @Column(name = "Date") 
    @Temporal(TemporalType.DATE) 
    private Date date; 

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "invoice") 
    private List<Invoiceitem> invoiceitemCollection; 

    @JoinColumn(name = "CustomerID", referencedColumnName = "CustomerID") 
    @ManyToOne(fetch = FetchType.LAZY,optional = false) 
    private Customer customerID; 

    // getter/setter 
} 

Invoiceitem

@Entity 
@Table(name = "invoiceitem") 
public class Invoiceitem implements Serializable { 
    private static final long serialVersionUID = 1L; 

    @EmbeddedId 
    protected InvoiceitemPK invoiceitemPK; 

    @Basic(optional = false) 
    @Column(name = "Quantity") 
    private int quantity; 

    @JoinColumn(name = "InvoiceID", referencedColumnName = "InvoiceID", insertable = false,   updatable = false) 
    @ManyToOne(optional = false) 
    private Invoice invoice; 

    @JoinColumn(name = "ProductID", referencedColumnName = "ProductID") 
    @ManyToOne(optional = false) 
    private Product productID; 

    // getter/setter 
} 

InvoiceItemPK

@Embeddable 
public class InvoiceitemPK implements Serializable { 

    @Column(name = "ItemID" ,nullable=false) 
    private long itemID; 

    @Column(name = "InvoiceID", nullable=false) 
    private long invoiceID; 

    // getter/setter 
} 

这是3层独立的应用程序,我需要做以下几点: 测试1.每个10-发票加10 invoiceitem .... ....

STEP 1,填写发票 - Invoiceitem:

for(int i = 0; i < invoiceNumber; i++){ 
// set invoice where invoiceNumber = 10, 100 
     Invoice invoice = new Invoice(); 
     String formatIn = "dd-MM-yyyy"; 
     SimpleDateFormat sdfi = new SimpleDateFormat(formatIn); 
     java.util.Date inDate = sdfi.parse("29-04-2011"); 
     java.sql.Date sqlDate = new java.sql.Date(inDate.getTime()); 

     invoice.setCustomerID(newCust); 
     invoice.setDate(sqlDate); 
     // set Invoiceitem 
     setInvoiceItem(prod, invItemNumber, invoice); 

     saveInvoice(invoice); 

} 

方法setInvoiceItem

List<Invoiceitem> invoiceItemList = new ArrayList<Invoiceitem>(); 
for(int i = 0; i < invItemNumber ; i++){ 
// set invoiceitem where invItemNumber = 10, 100 
     Invoiceitem invoiceItem = new Invoiceitem(); 
     int quantity = new RandomGeneratorForInteger().generateRandomNumber(10); 
     int genProductID = new RandomGeneratorForInteger().generateRandomNumber(ProductCollectionOpenJPA.getProdIDLi().size()); 
     Long pid = (Long) ProductCollectionOpenJPA.getProdIDLi().get(genProductID); 
     // set relation 
     invoiceItem.setInvoice(invoice); 
     invoiceItem.setProductID(prod = new Product(pid)); 
     invoiceItem.setQuantity(quantity); 
     invoiceItemList.add(invoiceItem); 
} 
invoice.setInvoiceitemCollection(invoiceItemList); 

我有通用的DAO

public void insert(E entity) { 
    try { 
     EntityManager em = getEntityManager(); 
     em.persist(entity); 
     } catch (Exception e) { 
     rollbackTransaction(); 
     e.printStackTrace(); 
     } 
     } 

STEP 2,InvoiceService - persit发票

public String save(Invoice invoice) { 
InvoiceDAO.log("saving Invoice---> InvoiceItem instance", Level.INFO, null); 
    try { 
     inDAO.beginTransaction(); 
    inDAO.insert(invoice); 

     for (int i = 0; i < invoice.getInvoiceitemCollection().size(); i++) { 
      InvoiceitemPK inItmPK = new InvoiceitemPK(); 

      inItmPK.setItemID(++i); 
      inItmPK.setInvoiceID(invoice.getInvoiceID()); 

      invoice.getInvoiceitemCollection().get(i).setInvoiceitemPK(inItmPK); 

     for (int i = 0; i < invoice.getInvoiceitemCollection().size(); i++) { 
      inDAO.insert(invoice); 

      } 
      inDAO.commitTransaction(); 
    } catch (Exception e) { 
     InvoiceDAO.log("save failed", Level.SEVERE, e); 
     return "Invoice are't saved"; 
    } 
    inDAO.closeEntityManager(); 
    InvoiceDAO.log("save successful", Level.INFO, null); 
    return "Invoice successfuly saved"; 
} 

运行的应用程序的错误获得: 1. org.apache.openjpa .persistence.ArgumentException:尝试将id“domainopenjpa.Invoiceitem-null”分配给新实例“[email protected] 11“失败; 2. org.apache.openjpa.persistence.ArgumentException:不能设定值

...

什么是坚持到发票数据库的最佳方式? 我在哪里犯了一个错误,以及如何纠正?

里克嗨,

异常堆栈看起来是这样的:

<openjpa-2.0.1-r422266:989424 fatal general error> org.apache.openjpa.persistence.PersistenceException: This operation failed for some instances. See the nested exceptions array for details. 
    at org.apache.openjpa.kernel.BrokerImpl.throwNestedExceptions(BrokerImpl.java:2493) 
    at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:2179) 
    at org.apache.openjpa.kernel.BrokerImpl.flushSafe(BrokerImpl.java:2037) 
    at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:1808) 
    at org.apache.openjpa.kernel.StateManagerImpl.assignObjectId(StateManagerImpl.java:609) 
    at org.apache.openjpa.kernel.StateManagerImpl.assignField(StateManagerImpl.java:696) 
    at org.apache.openjpa.kernel.StateManagerImpl.beforeAccessField(StateManagerImpl.java:1608) 
    at org.apache.openjpa.kernel.StateManagerImpl.accessingField(StateManagerImpl.java:1591) 
    at domainopenjpa.Invoice.pcGetinvoiceID(Invoice.java) 
... 
Caused by: <openjpa-2.0.1-r422266:989424 fatal general error> org.apache.openjpa.persistence.PersistenceException: The transaction has been rolled back. See the nested exceptions for details on the errors that occurred. 
    at org.apache.openjpa.kernel.BrokerImpl.newFlushException(BrokerImpl.java:2302) 
    at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:2139) 
    ... 77 more 
Caused by: <openjpa-2.0.1-r422266:989424 nonfatal user error> org.apache.openjpa.persistence.ArgumentException: cant-set-value 
    at org.apache.openjpa.jdbc.meta.strats.HandlerFieldStrategy.insert(HandlerFieldStrategy.java:132) 
    at org.apache.openjpa.jdbc.meta.FieldMapping.insert(FieldMapping.java:623) 
    at org.apache.openjpa.jdbc.kernel.AbstractUpdateManager.insert(AbstractUpdateManager.java:230) 
    at org.apache.openjpa.jdbc.kernel.AbstractUpdateManager.populateRowManager(AbstractUpdateManager.java:162) 
    at org.apache.openjpa.jdbc.kernel.AbstractUpdateManager.flush(AbstractUpdateManager.java:95) 
    at org.apache.openjpa.jdbc.kernel.AbstractUpdateManager.flush(AbstractUpdateManager.java:76) 
    at org.apache.openjpa.jdbc.kernel.JDBCStoreManager.flush(JDBCStoreManager.java:731) 
    at org.apache.openjpa.kernel.DelegatingStoreManager.flush(DelegatingStoreManager.java:131) 
    ... 78 more 
NestedThrowables: 
<openjpa-2.0.1-r422266:989424 nonfatal user error> org.apache.openjpa.persistence.ArgumentException: Attempt to assign id "domainopenjpa.Invoiceitem-null" to new instance "[email protected]" failed; there is already an object in the L1 cache with this id. You must delete this object (in a previous transaction or the current one) before reusing its id. This error can also occur when a horizontally or vertically mapped classes uses auto-increment application identity and does not use a hierarchy of application identity classes. 
FailedObject: [email protected] 
at org.apache.openjpa.kernel.ManagedCache.assignObjectId(ManagedCache.java:193) 
    at org.apache.openjpa.kernel.BrokerImpl.assignObjectId(BrokerImpl.java:4949) 
    at org.apache.openjpa.kernel.BrokerImpl.setStateManager(BrokerImpl.java:4046) 
    at org.apache.openjpa.kernel.StateManagerImpl.assertObjectIdAssigned(StateManagerImpl.java:636) 
    at org.apache.openjpa.kernel.StateManagerImpl.afterFlush(StateManagerImpl.java:1084) 
    at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:2162) 
    at org.apache.openjpa.kernel.BrokerImpl.flushSafe(BrokerImpl.java:2037) 
    at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:1808) 
    at org.apache.openjpa.kernel.StateManagerImpl.assignObjectId(StateManagerImpl.java:609) 
    at org.apache.openjpa.kernel.StateManagerImpl.assignField(StateManagerImpl.java:696) 
    at org.apache.openjpa.kernel.StateManagerImpl.beforeAccessField(StateManagerImpl.java:1608) 
    at org.apache.openjpa.kernel.StateManagerImpl.accessingField(StateManagerImpl.java:1591) 
    at domainopenjpa.Invoice.pcGetinvoiceID(Invoice.java) 
    at domainopenjpa.Invoice.getInvoiceID(Invoice.java:64) 

新的异常堆栈:

<openjpa-2.0.1-r422266:989424 fatal user error> org.apache.openjpa.persistence.InvalidStateException: Encountered unmanaged object in persistent field "domainopenjpa.Invoice.invoiceitemCollection<element:class domainopenjpa.Invoiceitem>" during flush. However, this field does not allow cascade persist. Set the cascade attribute for this field to CascadeType.PERSIST or CascadeType.ALL (JPA annotations) or "persist" or "all" (JPA orm.xml), or enable cascade-persist globally, or manually persist the related field value prior to flushing. You cannot flush unmanaged objects or graphs that have persistent associations to unmanaged objects. 
FailedObject: [email protected] 

回答

0

的问题是在你的public String save(Invoice invoice)方法。当您拨打inDAO.insert(invoice);即持续您的发票时,它将级联到所有InvoiceItems。 将您交给OpenJPA后,您不应该修改主键。

在您的保存方法中,您需要在调用inDAO.insert(invoice);之前设置InvoiceItemPK。另外,不要叫inDAO.insert(...)每个invoceItem,因为他们已经坚持由于您在关系设置@OneToMany(cascade = CascadeType.ALL, mappedBy = "invoice")

+0

好吧,但是当我尝试设置InvoiceitemPK时,我为InvoiceID,InvoiceID自动增量和因为我试图做的这种方式得到null。 – Milan 2011-06-06 23:38:42

+0

陷阱。您可以删除Cascade.ALL,并在您的Invoice上调用persist(并可能是flush)之后,将ID取出放入InvoiceItem。 – Rick 2011-06-07 01:39:30

+0

当我做下面的事情时,我得到了豁免女巫显示在上面,**新的异常堆栈:**。第一步将_ @ OneToMany(cascade = CascadeType.ALL,mappedBy =“invoice”)更改为@OneToMany(mappedBy =“invoice”)_,第二步在方法** Save(发票inv){** persist Invoice和getID,之后在for循环中创建InvoiceitemPK并为每个InvoiceItem设置InvoiceID和ItemID。 – Milan 2011-06-08 21:21:09

1

打开JPA ArgumentException的级联特性:

(由Yosi利)我有

插入行时openJpa的问题相同。 我得到了以下的ArgumentException:

<openjpa-1.2.4-SNAPSHOT-r422266:1481680 nonfatal user error> 
org.apache.openjpa.persistence.ArgumentException: 
Field "com.server.beans.entities.BalanceDetail.id" of "BalanceDetail 
id=BalanceDetailPK [relevanceDate=........], 
can not be set to "BalanceDetailPK [relevanceDate=........]" value. 
       WHICH WAS THE SAME VALUE .. 

问题是@Embeddable PK类BalanceDetailPK。 的@columns均产生(使用eclipse)用 “插入=假,可更新=假”

@Column(name="RELEVANCE_DATE", insertable=false, updatable=false) 
private java.util.Date relevanceDate; 

@Column(name="FND_ID", insertable=false, updatable=false) 
private Long fndId; 

删除这些属性:

@Column(name="RELEVANCE_DATE") 
private java.util.Date relevanceDate; 

@Column(name="FND_ID") 
private Long fndId; 

只是解决了这个问题。