-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 18 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Deletion of composite element fails
PostPosted: Wed Aug 27, 2003 3:07 am 
Regular
Regular

Joined: Wed Aug 27, 2003 2:55 am
Posts: 90
Location: Sweden
God morning,

I have implemented the Customer -> Order -> Product example from the ref. documentation.

I've modified the mapping to NOT use lazy loading and to use cascade on all.

The problem arise when I try to delete a Product associated with a Customer through an Order.

The following code is executed:

Code:
Set products = order.getProducts(); // The set contains instances of the composite element 'LineItem'
LineItem lineItem = (LineItem) products.iterator().next();
products.remove(lineItem);
session.delete(lineItem.getProduct()); // The LineItem holds the reference to the Product


I get a exception on the foreign keys constraints on table Products. It seems that Hibernate tries to delete from the Product table first when it should delete from LineItem table first.

I'm using Hibernate2, MS SQL Server 2000, J2SDK 1.4.1_02 and JSQLConnect JDBC driver.

Thanks!


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 27, 2003 3:20 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
No way!

Hibernate ALWAYS deletes collection rows before deleting any entities.

I suggest you enable Hibernate logging to see whats *really* going on!


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 27, 2003 3:31 am 
Regular
Regular

Joined: Wed Aug 27, 2003 2:55 am
Posts: 90
Location: Sweden
Hi,

I've enabled SQL logging nad the first SQL statement that is executed is:

Code:
DELETE FROM PRODUCTS WHERE product_id = ?



, and then I get the following exception message:

Code:
DELETE statement conflicted with COLUMN REFERENCE constraint 'FK_LINEITEM_PRODUCT'. The conflict occured in database 'Test', table 'LINEITEM', column 'product_id'.



Regards, Andreas Eriksson


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 27, 2003 3:38 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
I didn't say "SQL logging", I said "Hibernate logging". ie. log4j debug level logging.

P.S. quite likely the problem is that your composite element does not implement equals()/hashCode() as per the contract for java.util.Set.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 27, 2003 3:59 am 
Regular
Regular

Joined: Wed Aug 27, 2003 2:55 am
Posts: 90
Location: Sweden
Hi again,

How do I set the debug level on? Curently I'm using the default logging.properties in j2sdk1.4.1_02\jr\lib\, and level set to Level.ALL

Both equals() and hashCode() is implemented in the composite element class.

Regards, Andreas


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 27, 2003 4:39 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Dunno, I don't use that jdk crap.

Go download log4j. Then tweak the provided log4j.properties.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 27, 2003 4:53 am 
Regular
Regular

Joined: Wed Aug 27, 2003 2:55 am
Posts: 90
Location: Sweden
I've configured log4j to log on DEBUG level.

The SQL statement: delete from product where product_id = ?, is still performed as the first query.

My LineItem class is defined as following:

Code:
public class LineItem {
   
    private String guid;
    private String lineId; // Using literal strings
    private String order_guid;
    private String product_guid;

    public void setGuid(String guid) {
        this.guid = guid;
    }

    public String getGuid() {
        return guid;
    }

    public void setLineId(String lineId) {
        this.lineId = lineId;
    }

    public String getLineId() {
        return lineId;
    }

    public void setOrderGuid(String order_guid) {
        this.order_guid = order_guid;
    }

    public String getOrderGuid() {
        return guid;
    }

    public void setProductGuid(String product_guid) {
        this.product_guid = product_guid;
    }

    public String getProductGuid() {
        return product_guid;
    }

    /*
     * Relations
     */
    private Product product;

    public void setProduct(Product product) {
        this.product = product;
    }

    public Product getPRoduct() {
        return product;
    }

    /*
     * equals() and hashCode()
     */
    public boolean equals(Object object) {
        if (object == null) {
            return false;
        }

        if (object == this) {
            return true;
        }

        if (!(object instanceof LineItem)) {
            return false;
        }

        LineItem lineItem = (LineItem) object;

        if (!guid.equals(lineItem.guid)) {
            return false;
        }

        if (!lineId.equals(lineItem.lineId)) {
            return false;
        }

        if (!order_guid.equals(lineItem.order_guid)) {
            return false;
        }

        if (!product_guid.equals(lineItem.product_guid)) {
            return false;
        }

        return true;
    }

    public int hashCode() {
        int hash = 17;
        hash = 37 * hash + (guid == null ? 0 : guid.hashCode());
        hash = 37 * hash + (lineId == null ? 0 : lineId.hashCode());
        hash = 37 * hash + (order_guid == null ? 0 : order_guid.hashCode());
        hash = 37 * hash + (product_guid == null ? 0 : product_guid.hashCode());
        return hash;
    }
}


And the mapping file Order.hbm.xml:

Code:
<class="Order" table="Order" dynamic-update="true" dynamic-insert="true">

.
.
.

// Change to use a bag instead of set. Want to be able to store duplicates...

<bag name="Products" table="LineItem" cascade="all">
    <key column="order_guid"/>
    <composite-element class="LineItem">
        <property name="lineId"/>
        <many-to-one name="product" column="product_guid" class="Product" cascade="all"/>
    </composite-element>
</bag>


Any suggestions?

Regards, Andreas


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 27, 2003 4:57 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Ummmm. The whole point of enabling logging is so that you can show me the actual log. Like .... the whole thing .... not just a single SQL statement.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 27, 2003 4:58 am 
Regular
Regular

Joined: Wed Aug 27, 2003 2:55 am
Posts: 90
Location: Sweden
I'm sorry. My development computer is not connected to the Internet. I'm going to copy some logging for you...hold on!

Regards, Andreas


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 27, 2003 5:01 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
There is something very wrong with your LineItem class. It has a bunch of properties which are not mapped in the mapping file!

The only mapped properties are lineId and product. And product doesn't even appear in the equals()/hashCode()


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 27, 2003 5:02 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Oh, and its a <bag> so equals()/hashCode() are irrelevant.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 27, 2003 5:26 am 
Regular
Regular

Joined: Wed Aug 27, 2003 2:55 am
Posts: 90
Location: Sweden
Here's the logging from when I execute the code described above "session.delete(lineItem.getProduct())":

Code:
10:30:31,588 DEBUG SessionImpl:413 - opened session
10:30:31,588 DEBUG JDBCTransaction:36 - begin
10:30:31,588 DEBUG SessionImpl:896 - deleting a transient instance
10:30:31,588 DEBUG SessionImpl:941 - deleting [common.structures.Product#2C90AA1E-00F7-00F7-0003-FFFFF7424A39]
10:30:31,588 DEBUG JDBCTransaction:54 - commit
10:30:31,604 DEBUG SessionImpl:2011 - flushing session
10:30:31,604 DEBUG SessionImpl:2113 - Flushing entities and processing referenced collections
10:30:31,604 DEBUG SessionImpl:2397 - Processing unreferenced collections
10:30:31,604 DEBUG SessionImpl:2408 - Scheduling collection removes/(re)creates/updates
10:30:31,604 DEBUG SessionImpl:2023 - Flushed: 0 insertions, 0 updates, 1 deletions to 1 objects
10:30:31,604 DEBUG SessionImpl:2028 - Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections
10:30:31,604 DEBUG SessionImpl:2058 - executing flush
10:30:31,604 DEBUG EntityPersister:548 - Deleting entity: common.structures.Product#2C90AA1E-00F7-00F7-0003-FFFFF7424A39
10:30:31,604 DEBUG BatcherImpl:166 - about to open: 0 open PreparedStatements, 0 open ResultSets
10:30:31,604 DEBUG SessionFactoryImpl:526 - prepared statement get: delete from product where product_guid=?
Hibernate: delete from product where product_guid=?
10:30:31,604 DEBUG SessionFactoryImpl:536 - preparing statement
10:30:31,604 DEBUG StringType:44 - binding '2C90AA1E-00F7-00F7-0003-FFFFF7424A39' to parameter: 1
10:30:31,620 DEBUG JDBCExceptionReporter:36 - SQL Exception
com.jnetdirect.jsql.w: DELETE statement conflicted with COLUMN REFERENCE constraint 'FK_LINEITEM_PRODUCT'. The conflict occurred in database 'Test', table 'LINEITEM', column 'product_guid'.
   at com.jnetdirect.jsql.av.a(Unknown Source)
   at com.jnetdirect.jsql.ag.i(Unknown Source)
   at com.jnetdirect.jsql.ag.new(Unknown Source)
   at com.jnetdirect.jsql.ag.int(Unknown Source)
   at com.jnetdirect.jsql.ap.executeUpdate(Unknown Source)
   at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:207)
   at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:207)
   at net.sf.hibernate.impl.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:22)
   at net.sf.hibernate.persister.EntityPersister.delete(EntityPersister.java:575)
   at net.sf.hibernate.impl.ScheduledDeletion.execute(ScheduledDeletion.java:22)
   at net.sf.hibernate.impl.SessionImpl.executeAll(SessionImpl.java:2100)
   at net.sf.hibernate.impl.SessionImpl.execute(SessionImpl.java:2066)
   at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2005)
   at net.sf.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:57)
   at integration.dao.ProductDataManagerImpl.delete(ProductDataManagerImpl.java:38)
   at business.ProductController.delete(ProductController.java:15)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:324)
   at middle.CommandControllerImpl.doCommand(CommandControllerImpl.java:61)
   at nico.presentation.PersistenceManager.deleteProduct(PersistenceManager.java:94)
   at nico.presentation.HibernateClient.deleteMenu(HibernateClient.java:237)
   at nico.presentation.HibernateClient.updateMenu(HibernateClient.java:163)
   at nico.presentation.HibernateClient.start(HibernateClient.java:567)
   at nico.presentation.HibernateClient.main(HibernateClient.java:594)
10:30:31,620  WARN JDBCExceptionReporter:38 - SQL Error: 547, SQLState: 23000
10:30:31,620 ERROR JDBCExceptionReporter:46 - DELETE statement conflicted with COLUMN REFERENCE constraint 'FK_LINEITEM_PRODUCT'. The conflict occurred in database 'Test', table 'PRODUCT', column 'product_guid'.
10:30:31,620 DEBUG BatcherImpl:173 - done closing: 0 open PreparedStatements, 0 open ResultSets
10:30:31,620 DEBUG SessionFactoryImpl:554 - closing statement
10:30:31,635 ERROR JDBCExceptionReporter:37 - Could not synchronize database state with session
com.jnetdirect.jsql.w: DELETE statement conflicted with COLUMN REFERENCE constraint 'FK_LINEITEM_PRODUCT'. The conflict occurred in database 'Test', table 'LINEITEM', column 'product_guid'.
   at com.jnetdirect.jsql.av.a(Unknown Source)
   at com.jnetdirect.jsql.ag.i(Unknown Source)
   at com.jnetdirect.jsql.ag.new(Unknown Source)
   at com.jnetdirect.jsql.ag.int(Unknown Source)
   at com.jnetdirect.jsql.ap.executeUpdate(Unknown Source)
   at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:207)
   at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:207)
   at net.sf.hibernate.impl.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:22)
   at net.sf.hibernate.persister.EntityPersister.delete(EntityPersister.java:575)
   at net.sf.hibernate.impl.ScheduledDeletion.execute(ScheduledDeletion.java:22)
   at net.sf.hibernate.impl.SessionImpl.executeAll(SessionImpl.java:2100)
   at net.sf.hibernate.impl.SessionImpl.execute(SessionImpl.java:2066)
   at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2005)
   at net.sf.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:57)
   at integration.dao.ProductDataManagerImpl.delete(ProductDataManagerImpl.java:38)
   at business.ProductController.delete(ProductController.java:15)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:324)
   at middle.CommandControllerImpl.doCommand(CommandControllerImpl.java:61)
   at nico.presentation.PersistenceManager.deleteProduct(PersistenceManager.java:94)
   at nico.presentation.HibernateClient.deleteMenu(HibernateClient.java:237)
   at nico.presentation.HibernateClient.updateMenu(HibernateClient.java:163)
   at nico.presentation.HibernateClient.start(HibernateClient.java:567)
   at nico.presentation.HibernateClient.main(HibernateClient.java:594)
10:30:31,635 DEBUG SessionImpl:447 - transaction completion


Anf the SQL for creating the foreign key constraint:

Code:
ALTER TABLE [dbo].[LINEITEM] ADD
    CONSTRAINT [FK_LINEITEM_ORDER] FOREIGN KEY
    (
        [order_guid]
    ) REFERENCES [dbo].[ORDER] (
        [order_guid]
    ),
    CONSTRAINT [FK_LINEITEM_PRODUCT] FOREIGN KEY
    (
        [product_guid]
    ) REFERENCES [dbo].[PRODUCT] (
        [product_guid]
    )


Have seen your latest posting while I was modifying the logging. Do you have any suggestions on what I should change?

* Remove the equals()/hashCode()?
* Change the equals()/hashCode() to include Product?
* What more properties need to be mapped?

What else?

Regards, Andreas


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 27, 2003 5:32 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Ummm the object holding the collection is not even associated with the session!!

This is quite clear from the log.

Hibernate can't magically detect things you do to objects that are completely unrelated to any session.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 27, 2003 5:39 am 
Regular
Regular

Joined: Wed Aug 27, 2003 2:55 am
Posts: 90
Location: Sweden
First of all, thanks for taking the time!

Secondly, how do I associate an instance in UI to the session?

The workflow is like this:

1. Load object structure from db via Hibernate2 using the ThreadLocal pattern.

My data access objects calls ThreadLocal.currentSession(); in each of its persistency method to get an instance to the Session object.

2. The object structure is return to UI and the session is returned.

3. Make my modifications to the object in UI. Calling my data access object to make the modifications (in this case a delete). Data access object askes for ThreadLocal.currentSession() and performes the delete.

I know by now that I'm not making this quite right. But, how is the right way?

Regards, Andreas


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 27, 2003 5:40 am 
Regular
Regular

Joined: Wed Aug 27, 2003 2:55 am
Posts: 90
Location: Sweden
andreas_eriksson wrote:
First of all, thanks for taking the time!

Secondly, how do I associate an instance in UI to the session?

The workflow is like this:

1. Load object structure from db via Hibernate2 using the ThreadLocal pattern.

My data access objects calls ThreadLocal.currentSession(); in each of its persistency method to get an instance to the Session object.

2. The object structure is return to UI and the session is returned at the end of the data access method.

3. Make my modifications to the object in UI. Calling my data access object to make the modifications (in this case a delete). Data access object askes for ThreadLocal.currentSession() and performes the delete.

I know by now that I'm not making this quite right. But, how is the right way?

Regards, Andreas


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 18 posts ]  Go to page 1, 2  Next

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.