У меня есть следующие объекты:
Счет
@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
}
Это трехуровневое автономное приложение, и мне нужно сделать следующее:
Тест 1. Для каждого 10-инвойса добавьте 10-инвойс
....
....
ШАГ 1 , заполнить Счет - Счет-фактура:
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();
}
}
ШАГ 2, InvoiceService - счет-фактура
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: попытка присвоить идентификатор «domainopenjpa.Invoiceitem-null» новому экземпляру «domainopenjpa.Invoiceitem@4fdf11» не удалась;
2. org.apache.openjpa.persistence.ArgumentException: cant-set-value
...
Каков наилучший способ сохранить Invoice в БД?
Где я ошибся и как исправить?
Привет Рик,
Стек исключений выглядит так:
<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 "domainopenjpa.Invoiceitem@4fdf11" 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: domainopenjpa.Invoiceitem@4fdf11
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: domainopenjpa.Invoiceitem@939bdb