2011-06-03 62 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; 

只是解決了這個問題。