OpenJPA 级联使用 @EmbeddedId 保持一对多

发布于 2024-11-13 06:34:24 字数 9708 浏览 2 评论 0原文

我有以下实体:

Invoice

@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 张发票项目 .... ....

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 - 保留发票

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”分配给新实例“domainopenjpa.Invoiceitem@4fdf11”失败; 2. org.apache.openjpa.persistence.ArgumentException: cant-set-value

...

将发票保存到数据库的最佳方法是什么? 我哪里做错了,如何改正?

嗨,Rick,

异常堆栈如下所示:

<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

I have the following entities:

Invoice

@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
}

It's 3-tier stand alone app, and I need to do following:
test 1. for each of 10-invoice add 10-invoiceitem
....
....

STEP 1, populate Invoice - 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);

}

method 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); 

I have generic DAO

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

STEP 2, InvoiceService - persit invoice

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";
}

Running applications are obtained by errors:
1. org.apache.openjpa.persistence.ArgumentException: Attempt to assign id "domainopenjpa.Invoiceitem-null" to new instance "domainopenjpa.Invoiceitem@4fdf11" failed;
2. org.apache.openjpa.persistence.ArgumentException: cant-set-value

...

What is the best way to persist Invoice into DB?
Where I made ​​a mistake, and how to correct?

Hi Rick,

Exception stack looks like this:

<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)

New Exception stack:

<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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

扮仙女 2024-11-20 06:34:24

Open Jpa ArgumentException:

插入行时我遇到了与 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 都是用“insertable=false, updatable=false”生成的(使用 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;

刚刚解决了问题。

Open Jpa ArgumentException:

I had the same problem with openJpa when inserting rows.
I got the following 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 ..

The problem was the @Embeddable PK class BalanceDetailPK.
The @Columns were all generated (using eclipse) with "insertable=false, updatable=false"

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

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

Removing these attributes :

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

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

just solved the problem.

°如果伤别离去 2024-11-20 06:34:24

问题出在您的 public String save(Invoice Invoice) 方法中。当您调用 inDAO.insert(invoice); 时,会保留您的发票,并且它会级联到所有 InvoiceItems。 在将主键移交给 OpenJPA 后,您不应对其进行修改。

在您的保存方法中,您需要在调用 inDAO.insert(invoice); 之前设置 InvoiceItemPK;代码>.另外,不要为每个 invoceItem 调用 inDAO.insert(...),因为由于您在关系 @OneToMany(cascade = CascadeType.全部,mappedBy =“发票”)

The problem is in your public String save(Invoice invoice) method. When you call inDAO.insert(invoice); that is persisting your Invoice and it is cascading to all InvoiceItems. You shouldn't be modifying a primary key after you hand it over to OpenJPA.

In your save method, you need to set the InvoiceItemPK prior to calling inDAO.insert(invoice);. Also, don't call inDAO.insert(...) for each invoceItem as they are already persisted due to the Cascade property that you set on the relationship @OneToMany(cascade = CascadeType.ALL, mappedBy = "invoice")

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文