Search code examples
javajpaeclipselinkderby

JPA OneToMany With Identity Generated Parent ID persist Error


PLease guys advice I have a problem when persisting a OneToMany relationship in JPA, see this example,

THE PARENT CALSS

    @Entity
    @Table(name="SALES_INVOICES")
    public class SalesInvoice {

        @Id
        @Column(name="INV_ID")
        @GeneratedValue(strategy=GenerationType.IDENTITY)
        private long invoiceID;

        @Column(name="INV_NO", nullable=false)
        private long invoiceNumber;

        @Column(name="DOC_TYPE")
        private String docType;

        @Column(name="INV_TOTAL")
        private BigDecimal totalInvoice;

        @Column(name="NOTES")
        private String notes;

        @Column(name="STORE_ID")
        private int storeID;

        @Column(name="INV_DATE")
        private Date invoiceDate;

        @Column(name="CUST_ID",nullable=true)
        private int cusomerID;

        @Column(name="OPER_TYPE")
        private String operType;

        @Column(name="TECH_ID", nullable=true)
        private int techID;

        @ManyToOne
        @PrimaryKeyJoinColumn(name="STORE_ID", referencedColumnName="STORE_ID")
        private Store store;

        @ManyToOne
        @PrimaryKeyJoinColumn(name="CUST_ID", referencedColumnName="CUST_ID")
        private Customer customer;

        @OneToMany(mappedBy="invoice",cascade=CascadeType.ALL,fetch=FetchType.LAZY)
        @JoinColumn(name="INV_ID")
        private List<InvoiceLine> lines;

        @ManyToOne
        @PrimaryKeyJoinColumn(name="TECH_ID",referencedColumnName="TECH_ID")
        private Technician technician;

        /**
         * @return the operTypeID
         */
        public String getOperType() {
            return operType;
        }

        /**
         * @param operTypeID the operTypeID to set
         */
        public void setOperType(String operType) {
            this.operType = operType;
        }

        /**
         * @return the techID
         */
        public int getTechID() {
            return techID;
        }

        /**
         * @param techID the techID to set
         */
        public void setTechID(int techID) {
            this.techID = techID;
        }

        /**
         * @return the lines
         */
        public List<InvoiceLine> getLines() {
            return lines;
        }

        /**
         * @param lines the lines to set
         */
        public void setLines(List<InvoiceLine> lines) {
            this.lines = lines;
        }

        /**
         * @return the technician
         */
        public Technician getTechnician() {
            return technician;
        }

        /**
         * @param technician the technician to set
         */
        public void setTechnician(Technician technician) {
            this.technician = technician;
        }

        /**
         * @return the cusomerID
         */
        public int getCusomerID() {
            return cusomerID;
        }

        /**
         * @param cusomerID the cusomerID to set
         */
        public void setCusomerID(int cusomerID) {
            this.cusomerID = cusomerID;
        }

        /**
         * @return the store
         */
        public Store getStore() {
            return store;
        }

        /**
         * @param store the store to set
         */
        public void setStore(Store store) {
            this.store = store;
        }

        /**
         * @return the customer
         */
        public Customer getCustomer() {
            return customer;
        }

        /**
         * @param customer the customer to set
         */
        public void setCustomer(Customer customer) {
            this.customer = customer;
        }

        public SalesInvoice(){}

        /**
         * @return the invoiceID
         */
        public long getInvoiceID() {
            return invoiceID;
        }

        /**
         * @param invoiceID the invoiceID to set
         */
        public void setInvoiceID(long invoiceID) {
            this.invoiceID = invoiceID;
        }

        /**
         * @return the invoiceNumber
         */
        public long getInvoiceNumber() {
            return invoiceNumber;
        }

        /**
         * @param invoiceNumber the invoiceNumber to set
         */
        public void setInvoiceNumber(long invoiceNumber) {
            this.invoiceNumber = invoiceNumber;
        }

        /**
         * @return the docType
         */
        public String getDocType() {
            return docType;
        }

        /**
         * @param docType the docType to set
         */
        public void setDocType(String docType) {
            this.docType = docType;
        }

        /**
         * @return the totalInvoice
         */
        public BigDecimal getTotalInvoice() {
            return totalInvoice;
        }

        /**
         * @param totalInvoice the totalInvoice to set
         */
        public void setTotalInvoice(BigDecimal totalInvoice) {
            this.totalInvoice = totalInvoice;
        }

        /**
         * @return the notes
         */
        public String getNotes() {
            return notes;
        }

        /**
         * @param notes the notes to set
         */
        public void setNotes(String notes) {
            this.notes = notes;
        }

        /**
         * @return the storeID
         */
        public int getStoreID() {
            return storeID;
        }

        /**
         * @param storeID the storeID to set
         */
        public void setStoreID(int storeID) {
            this.storeID = storeID;
        }

        /**
         * @return the invoiceDate
         */
        public Date getInvoiceDate() {
            return invoiceDate;
        }

        /**
         * @param invoiceDate the invoiceDate to set
         */
        public void setInvoiceDate(Date invoiceDate) {
            this.invoiceDate = invoiceDate;
        }



    }

    //////////////////////////////////////////////
    HERE IS THE CHILD CLASS....
    @Entity
    @Table(name="INV_LINES")
    public class InvoiceLine {

        @Id
        @Column(name="LINE_ID")
        @GeneratedValue(strategy=GenerationType.IDENTITY)
        private long lineID;

        @Column(name="INV_ID")
        private long invoiceID;


        @Column(name="STOCK_ITEM")
        private String stockItem;

        @Column(name="QTY")
        private int quantity;
        @Column(name="TOTAL_PRICE")
        private BigDecimal totalPrice;

        @Column(name="NOTES")
        private String notes;

        @Column(name="WARRANTY")
        private boolean warranted;

        @Column(name="DAYS_WARRANTY")
        private int warrantyDays;

        @ManyToOne
        @PrimaryKeyJoinColumn(name="STOCK_ITEM",referencedColumnName="ITEM_ID")
        private StockItem item;

        @ManyToOne(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
        @PrimaryKeyJoinColumn(name="INV_ID", referencedColumnName="INV_ID")
        private SalesInvoice invoice;





        /**
         * @return the invoiceID
         */
        public long getInvoiceID() {
            return invoiceID;
        }

        /**
         * @param invoiceID the invoiceID to set
         */
        public void setInvoiceID(long invoiceID) {
            this.invoiceID = invoiceID;
        }

        /**
         * @return the invoice
         */
        public SalesInvoice getInvoice() {
            return invoice;
        }

        /**
         * @param invoice the invoice to set
         */
        public void setInvoice(SalesInvoice invoice) {
            this.invoice = invoice;
            this.invoiceID = invoice.getInvoiceID();

        }
        public InvoiceLine(){}

        /**
         * @return the lineID
         */
        public long getLineID() {
            return lineID;
        }

        /**
         * @param lineID the lineID to set
         */
        public void setLineID(long lineID) {
            this.lineID = lineID;
        }

        /**
         * @return the stockItem
         */
        public String getStockItem() {
            return stockItem;
        }

        /**
         * @param stockItem the stockItem to set
         */
        public void setStockItem(String stockItem) {
            this.stockItem = stockItem;
        }

        /**
         * @return the quantity
         */
        public int getQuantity() {
            return quantity;
        }

        /**
         * @param quantity the quantity to set
         */
        public void setQuantity(int quantity) {
            this.quantity = quantity;
        }

        /**
         * @return the totalPrice
         */
        public BigDecimal getTotalPrice() {
            return totalPrice;
        }

        /**
         * @param totalPrice the totalPrice to set
         */
        public void setTotalPrice(BigDecimal totalPrice) {
            this.totalPrice = totalPrice;
        }

        /**
         * @return the notes
         */
        public String getNotes() {
            return notes;
        }

        /**
         * @param notes the notes to set
         */
        public void setNotes(String notes) {
            this.notes = notes;
        }

        /**
         * @return the warranted
         */
        public boolean isWarranted() {
            return warranted;
        }

        /**
         * @param warranted the warranted to set
         */
        public void setWarranted(boolean warranted) {
            this.warranted = warranted;
        }

        /**
         * @return the warrantyDays
         */
        public int getWarrantyDays() {
            return warrantyDays;
        }

        /**
         * @param warrantyDays the warrantyDays to set
         */
        public void setWarrantyDays(int warrantyDays) {
            this.warrantyDays = warrantyDays;
        }

        /**
         * @return the item
         */
        public StockItem getItem() {
            return item;
        }

        /**
         * @param item the item to set
         */
        public void setItem(StockItem item) {
            this.item = item;
        }



    }

WHENE TRYING to persist SalesInvoice I got the following Error

the problem is here:

    [EL Info]: 2014-11-17 16:42:24.445--ServerSession(314966354)--EclipseLink, version: Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd
    [EL Warning]: metadata: 2014-11-17 16:42:39.74--ServerSession(314966354)--Reverting the lazy setting on the OneToOne or ManyToOne attribute [invoice] for the entity class [class com.mehwar.model.InvoiceLine] since weaving was not enabled or did not occur.
    [EL Info]: connection: 2014-11-17 16:42:39.866--ServerSession(314966354)--file:/C:/Users/Omar/workspace/MehwarBOF/bin/_ss login successful
    [EL Warning]: 2014-11-17 16:43:17.85--UnitOfWork(464433398)--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException
    Internal Exception: java.sql.SQLIntegrityConstraintViolationException: INSERT on table 'INV_LINES' caused a violation of foreign key constraint 'INV_LINES_INV_ID' for key (0).  The statement has been rolled back.
    Error Code: 20000
    Call: INSERT INTO INV_LINES (INV_ID, NOTES, QTY, STOCK_ITEM, TOTAL_PRICE, WARRANTY, DAYS_WARRANTY) VALUES (?, ?, ?, ?, ?, ?, ?)
        bind => [7 parameters bound]
    Query: InsertObjectQuery(com.mehwar.model.InvoiceLine@28444350)
    Exception in thread "AWT-EventQueue-0" javax.persistence.RollbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException
    Internal Exception: java.sql.SQLIntegrityConstraintViolationException: INSERT on table 'INV_LINES' caused a violation of foreign key constraint 'INV_LINES_INV_ID' for key (0).  The statement has been rolled back.
    Error Code: 20000
    Call: INSERT INTO INV_LINES (INV_ID, NOTES, QTY, STOCK_ITEM, TOTAL_PRICE, WARRANTY, DAYS_WARRANTY) VALUES (?, ?, ?, ?, ?, ?, ?)
        bind => [7 parameters bound]
    Query: InsertObjectQuery(com.mehwar.model.InvoiceLine@28444350)
        at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:157)
        at com.mehwar.controllers.SalesInvController.actionPerformed(SalesInvController.java:94)
        at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
        at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
        at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
        at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
        at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
        at java.awt.Component.processMouseEvent(Unknown Source)
        at javax.swing.JComponent.processMouseEvent(Unknown Source)
        at java.awt.Component.processEvent(Unknown Source)
        at java.awt.Container.processEvent(Unknown Source)
        at java.awt.Component.dispatchEventImpl(Unknown Source)
        at java.awt.Container.dispatchEventImpl(Unknown Source)
        at java.awt.Component.dispatchEvent(Unknown Source)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
        at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
        at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
        at java.awt.Container.dispatchEventImpl(Unknown Source)
        at java.awt.Window.dispatchEventImpl(Unknown Source)
        at java.awt.Component.dispatchEvent(Unknown Source)
        at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
        at java.awt.EventQueue.access$400(Unknown Source)
        at java.awt.EventQueue$3.run(Unknown Source)
        at java.awt.EventQueue$3.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
        at java.awt.EventQueue$4.run(Unknown Source)
        at java.awt.EventQueue$4.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
        at java.awt.EventQueue.dispatchEvent(Unknown Source)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
        at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
        at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
        at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
        at java.awt.EventDispatchThread.run(Unknown Source)
    Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException
    Internal Exception: java.sql.SQLIntegrityConstraintViolationException: INSERT on table 'INV_LINES' caused a violation of foreign key constraint 'INV_LINES_INV_ID' for key (0).  The statement has been rolled back.
    Error Code: 20000
    Call: INSERT INTO INV_LINES (INV_ID, NOTES, QTY, STOCK_ITEM, TOTAL_PRICE, WARRANTY, DAYS_WARRANTY) VALUES (?, ?, ?, ?, ?, ?, ?)
        bind => [7 parameters bound]
    Query: InsertObjectQuery(com.mehwar.model.InvoiceLine@28444350)
        at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:331)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:900)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeNoSelect(DatabaseAccessor.java:962)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:631)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:558)
        at org.eclipse.persistence.internal.sessions.AbstractSession.basicExecuteCall(AbstractSession.java:2002)
        at org.eclipse.persistence.sessions.server.ClientSession.executeCall(ClientSession.java:298)
        at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:242)
        at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:228)
        at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.insertObject(DatasourceCallQueryMechanism.java:377)
        at org.eclipse.persistence.internal.queries.StatementQueryMechanism.insertObject(StatementQueryMechanism.java:165)
        at org.eclipse.persistence.internal.queries.StatementQueryMechanism.insertObject(StatementQueryMechanism.java:180)
        at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.insertObjectForWrite(DatabaseQueryMechanism.java:489)
        at org.eclipse.persistence.queries.InsertObjectQuery.executeCommit(InsertObjectQuery.java:80)
        at org.eclipse.persistence.queries.InsertObjectQuery.executeCommitWithChangeSet(InsertObjectQuery.java:90)
        at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.executeWriteWithChangeSet(DatabaseQueryMechanism.java:301)
        at org.eclipse.persistence.queries.WriteObjectQuery.executeDatabaseQuery(WriteObjectQuery.java:58)
        at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:899)
        at org.eclipse.persistence.queries.DatabaseQuery.executeInUnitOfWork(DatabaseQuery.java:798)
        at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWorkObjectLevelModifyQuery(ObjectLevelModifyQuery.java:108)
        at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWork(ObjectLevelModifyQuery.java:85)
        at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2896)
        at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1804)
        at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1786)
        at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1737)
        at org.eclipse.persistence.internal.sessions.CommitManager.commitNewObjectsForClassWithChangeSet(CommitManager.java:226)
        at org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsForClassWithChangeSet(CommitManager.java:193)
        at org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsWithChangeSet(CommitManager.java:138)
        at org.eclipse.persistence.internal.sessions.AbstractSession.writeAllObjectsWithChangeSet(AbstractSession.java:4207)
        at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1441)
        at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1531)
        at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitRootUnitOfWork(RepeatableWriteUnitOfWork.java:277)
        at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitAndResume(UnitOfWorkImpl.java:1169)
        at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:132)
        ... 37 more
    Caused by: java.sql.SQLIntegrityConstraintViolationException: INSERT on table 'INV_LINES' caused a violation of foreign key constraint 'INV_LINES_INV_ID' for key (0).  The statement has been rolled back.
        at org.apache.derby.client.am.SQLExceptionFactory40.getSQLException(Unknown Source)
        at org.apache.derby.client.am.SqlException.getSQLException(Unknown Source)
        at org.apache.derby.client.am.PreparedStatement.executeUpdate(Unknown Source)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:890)
        ... 69 more
    Caused by: org.apache.derby.client.am.SqlException: INSERT on table 'INV_LINES' caused a violation of foreign key constraint 'INV_LINES_INV_ID' for key (0).  The statement has been rolled back.
        at org.apache.derby.client.am.Statement.completeExecute(Unknown Source)
        at org.apache.derby.client.net.NetStatementReply.parseEXCSQLSTTreply(Unknown Source)


at org.apache.derby.client.net.NetStatementReply.readExecute(Unknown Source)
    at org.apache.derby.client.net.StatementReply.readExecute(Unknown Source)
    at org.apache.derby.client.net.NetPreparedStatement.readExecute_(Unknown Source)
    at org.apache.derby.client.am.PreparedStatement.readExecute(Unknown Source)
    at org.apache.derby.client.am.PreparedStatement.flowExecute(Unknown Source)
    at org.apache.derby.client.am.PreparedStatement.executeUpdateX(Unknown Source)
    ... 71 more

THANK YOU ALL


Solution

  • Your mapppings are incorrect; you are using @PrimaryKeyJoinColumn on OneToOne and ManyToOne mappings when you should be using @JoinColumn, and are using @JoinColumn on your OneToMany mapping when it should be specifying that it is mapped by the other relationship.

    in SalesInvoice try:

        @ManyToOne
        @JoinColumn(name="STORE_ID", referencedColumnName="STORE_ID")
        private Store store;
    
        @ManyToOne
        @JoinColumn(name="CUST_ID", referencedColumnName="CUST_ID")
        private Customer customer;
    
        @OneToMany(mappedBy="invoice",cascade=CascadeType.ALL,fetch=FetchType.LAZY)
        private List<InvoiceLine> lines;
    
        @ManyToOne
        @JoinColumn(name="TECH_ID",referencedColumnName="TECH_ID")
        private Technician technician;
    

    While in InvoiceLine, try:

        @ManyToOne(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
        @JoinColumn(name="INV_ID", referencedColumnName="INV_ID")
        private SalesInvoice invoice;
    

    This is how you would make the SalesInvoice - InvoiceLine a bidirectional relationship. Don't forget that the application is responsible for keeping both sides of the bidirectional relationship in synch with each other and the database. JPA will not do it for you, and the cache will become corrupt.

    You also need to either remove the long invoiceID mapping, make it read-only or set the value, as this is what is used to set the "INV_ID" field in your previous entity setup - it is likely why you were using @PrimaryKeyJoinColumn as the provider would have complained you had multiple writable mappings otherwise. Evaluate its purpose and remove it if it isn't needed, otherwise I would make it read-only using:

        @Column(name="INV_ID", insertable=false, updatable=false)
        private long invoiceID;
    

    As this will allow you to keep the attribute in the entity, but let JPA set it using the value from the invoice relationship instead.