Hi Folks,
I'll apologise now if this question has an obvious answer, but I've been stumped for days now even after trawling this forum and other online examples...
I've got a fairly typical 'user' / 'basket' / 'basket item' arrangement for an online shop. Each User has exactly 1 Basket, and BasketItems can be added to the Basket. The trouble is that when I come to remove BasketItems from the Basket, and persist the updated User object, the database doesn't reflect the changes made to the BasketItems collection.
I've set cascade="all" in both directions in the Basket and BasketItem mapping files (just in case ;) ), but this doesn't seem to have made a difference. I guess it must be a mapping file problem but I really can't figure out what.
I've written a simple junit testcase (below) to demonstrate the problem.
If anyone can offer some advice I'd be really grateful...
Cheers,
Richard.
Hibernate version:
3.1.3
Mapping documents:
==================================
User.hbm.xml
==================================
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="uk.co.plugandplaydesign.dal.hibernate.User" table="user"
schema="public" lazy="false">
<id name="id" type="long" column="id" length="8">
<generator class="increment" />
</id>
<property name="emailAddress" type="string"
column="emailaddress" not-null="true" length="45" />
<property name="firstName" type="string" column="firstname"
length="25" />
<property name="lastName" type="string" column="lastname"
not-null="true" length="25" />
<property name="password" type="string" column="password"
not-null="true" length="15" />
<property name="staff" type="boolean" column="staff"
not-null="true" length="1" />
<property name="dateRegistered" type="date" column="dateregistered"
not-null="true" length="4" />
<property name="registrationKey" type="string" column="registrationkey"
not-null="true" length="16" />
<property name="title" type="string" column="title"
length="10" />
<property name="validated" type="boolean" column="validated"
not-null="true" length="1" />
<set name="contacts" cascade="all" inverse="true">
<key column="userid"/>
<one-to-many class="uk.co.plugandplaydesign.dal.hibernate.Contact"/>
</set>
<one-to-one name="basket" class="uk.co.plugandplaydesign.dal.hibernate.Basket" constrained="true" cascade="all"/>
</class>
</hibernate-mapping>
==================================
Basket.hbm.xml
==================================
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="uk.co.plugandplaydesign.dal.hibernate.Basket"
table="basket" schema="public" lazy="false">
<id name="id" type="long" column="id" length="8">
<generator class="increment" />
</id>
<property name="userid" type="long" column="userid"
not-null="true" length="8" />
<one-to-one name="user" class="uk.co.plugandplaydesign.dal.hibernate.User" cascade="all"/>
<set name="basketItems" inverse="true" cascade="all">
<key column="basketid"/>
<one-to-many class="uk.co.plugandplaydesign.dal.hibernate.BasketItem"/>
</set>
</class>
</hibernate-mapping>
==================================
BasketItem.hbm.xml
==================================
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="uk.co.plugandplaydesign.dal.hibernate.BasketItem"
table="basketitems" schema="public" lazy="false">
<id name="id" type="long" column="id" length="8">
<generator class="increment" />
</id>
<!-- <property name="basketid" type="long" column="basketid"
not-null="true" length="8" /> -->
<property name="productid" type="long" column="productid"
not-null="true" length="8" />
<property name="quantity" type="long" column="quantity"
not-null="true" length="8" />
<many-to-one name="basket" column="basketid" not-null="true" cascade="all"/>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():
User, Basket and BasketItem are really just beans with getters and setters. The only exception is that when invoking User.setBasket(Basket b), b is also assigned a reference to the parent User. This is similarly true for BasketItems (which are each assigned a reference to the parent Basket). I'll post the code if it's needed.
public void testDelete() {
//ser up the user
User user = new User();
user.setEmailAddress("john.smith@somedomain.com");
user.setFirstName("John");
user.setLastName("Smith");
user.setPassword("password1");
user.setTitle("Mr");
//create a contact
Contact contact = new Contact();
contact.setAddressline1("10 Some Street");
contact.setCity("London");
contact.setCountry("UK");
contact.setPostcode("NW1");
contact.setTelephonenumber("012345 12345678");
user.addContact(contact);
//create an item for the basket
BasketItem basketItem = new BasketItem();
basketItem.setProductid(1);
basketItem.setQuantity(1);
//add the item to the basket
user.getBasket().addBasketItem(basketItem);
//persist the user and all its child objects
user = persistUser(user);
Query query = HibernateUtil.currentSession(hibernateConfig).createQuery("from User where emailaddress =
'john.smith@somedomain.com'");
List users = query.list();
//get an instance of the persisted user
user = (User)users.get(0);
Basket basket = user.getBasket();
//empty the basket
basket.emptyBasket();
//persist the user again
user = persistUser(user);
query = HibernateUtil.currentSession(hibernateConfig).createQuery("from User where emailaddress =
'john.smith@somedomain.com'");
users = query.list();
//get the persisted user again
user = (User)users.get(0);
//THIS BIT FAILS :-(
//assert that there are no items in the basket
assertTrue(user.getBasket().getBasketItems().isEmpty());
}
private User persistUser(User user) {
Transaction tx = null;
Session session = null;
User result = null;
try {
session = HibernateUtil.currentSession(this.hibernateConfig);
tx = session.beginTransaction();
result = (User)session.merge(user);
tx.commit();
session.flush();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
session.close();
}
return result;
}
Full stack trace of any exception that occurs:
No exception thrown
Name and version of the database you are using:
Postgres 8.1.4
The generated SQL (show_sql=true):
Hibernate: select max(id) from public.basket
Hibernate: select max(id) from public.basketitems
Hibernate: select max(id) from public.user
Hibernate: select max(id) from public.contact
Hibernate: insert into public.basket (userid, id) values (?, ?)
Hibernate: insert into public.basketitems (productid, quantity, basketid, id) values (?, ?, ?, ?)
Hibernate: insert into public.user (emailaddress, firstname, lastname, password, staff, dateregistered, registrationkey, title, validated, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into public.contact (addressline1, addressline2, city, postcode, telephonenumber, mobilenumber, county, country, userid, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: update public.basket set userid=? where id=?
Hibernate: select user0_.id as id2_, user0_.emailaddress as emailadd2_2_, user0_.firstname as firstname2_, user0_.lastname as lastname2_, user0_.password as password2_, user0_.staff as staff2_, user0_.dateregistered as dateregi7_2_, user0_.registrationkey as registra8_2_, user0_.title as title2_, user0_.validated as validated2_ from public.user user0_ where emailaddress='john.smith@somedomain.com'
Hibernate: select basket0_.id as id1_1_, basket0_.userid as userid1_1_, user1_.id as id2_0_, user1_.emailaddress as emailadd2_2_0_, user1_.firstname as firstname2_0_, user1_.lastname as lastname2_0_, user1_.password as password2_0_, user1_.staff as staff2_0_, user1_.dateregistered as dateregi7_2_0_, user1_.registrationkey as registra8_2_0_, user1_.title as title2_0_, user1_.validated as validated2_0_ from public.basket basket0_ left outer join public.user user1_ on basket0_.id=user1_.id where basket0_.id=?
Hibernate: select basket0_.id as id1_1_, basket0_.userid as userid1_1_, user1_.id as id2_0_, user1_.emailaddress as emailadd2_2_0_, user1_.firstname as firstname2_0_, user1_.lastname as lastname2_0_, user1_.password as password2_0_, user1_.staff as staff2_0_, user1_.dateregistered as dateregi7_2_0_, user1_.registrationkey as registra8_2_0_, user1_.title as title2_0_, user1_.validated as validated2_0_ from public.basket basket0_ left outer join public.user user1_ on basket0_.id=user1_.id where basket0_.id=?
Hibernate: select user0_.id as id2_, user0_.emailaddress as emailadd2_2_, user0_.firstname as firstname2_, user0_.lastname as lastname2_, user0_.password as password2_, user0_.staff as staff2_, user0_.dateregistered as dateregi7_2_, user0_.registrationkey as registra8_2_, user0_.title as title2_, user0_.validated as validated2_ from public.user user0_ where emailaddress='john.smith@somedomain.com'
Hibernate: select basket0_.id as id1_1_, basket0_.userid as userid1_1_, user1_.id as id2_0_, user1_.emailaddress as emailadd2_2_0_, user1_.firstname as firstname2_0_, user1_.lastname as lastname2_0_, user1_.password as password2_0_, user1_.staff as staff2_0_, user1_.dateregistered as dateregi7_2_0_, user1_.registrationkey as registra8_2_0_, user1_.title as title2_0_, user1_.validated as validated2_0_ from public.basket basket0_ left outer join public.user user1_ on basket0_.id=user1_.id where basket0_.id=?
Hibernate: select basket0_.id as id1_1_, basket0_.userid as userid1_1_, user1_.id as id2_0_, user1_.emailaddress as emailadd2_2_0_, user1_.firstname as firstname2_0_, user1_.lastname as lastname2_0_, user1_.password as password2_0_, user1_.staff as staff2_0_, user1_.dateregistered as dateregi7_2_0_, user1_.registrationkey as registra8_2_0_, user1_.title as title2_0_, user1_.validated as validated2_0_ from public.basket basket0_ left outer join public.user user1_ on basket0_.id=user1_.id where basket0_.id=?
Hibernate: select basketitem0_.basketid as basketid1_, basketitem0_.id as id1_, basketitem0_.id as id7_0_, basketitem0_.productid as productid7_0_, basketitem0_.quantity as quantity7_0_, basketitem0_.basketid as basketid7_0_ from public.basketitems basketitem0_ where basketitem0_.basketid=?