Hi, I am developing a jsp web application using Struts and Hibernate.
The web application is an online ordering system for a food home delivery service where customers can place food orders online.
Now, when a customer first visits the web site the customer shall first register his/her details including a username and a password.
The username and password will be used by the customer after the first visit, where the customer can login instead of registering again.
Pretty much basic, like other web applications.
Now the problem is that when a customer registers his/her details I want the web application to store the "Customer" object in the database eventhough the customer has not placed an order yet.
This means that once registered whether the customer has placed and order or not, the customer can login when returning to the site.
The customer class also stores a "Card" class and a "Set" of customerorders which is of type "CustomerOrder".
When I try to save the customer class though no "Card" or customerorders have been added to the "Set" Hibernate does not seem to like it.
Hibernate says that
Code:
Hibernate : update customerorder set customerorders=? where id=?
- Could not synchronise database state with session
net.sf.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing:
model.customer.CustomerOrder..............
It simply says that I should also create and intialise a "Card", or a "CustomerOrder" object to the "Set" of customerorders.
But I cannot initialise a "Card" or a "CustomerOrder" object straight way,
I have to wait for the "Customer" to give his/her "Card" details and also
place a "CustomerOrder" then I can save these objects in the "Customer" class.
Now this problem is simpler than I have put it, I have only tried to make clear what I want to achieve.
I believe the problem lies in my mapping configuration, for example a
"Customer" class has a one-to-many relationship with a "CustomerOrder"
class.
But the "Customer" class shall be able to be saved having null reference to "CustomerOrder" or "Card" class.
The "Customer" class shall be able to add a "Card" or a "CustomerOrder" object at later time....
This kind of problem occurs actually to many of my classes since many of them are aggregated with other classes, but the principle should be the same, if I resolve this problem.
here below is code for my "Customer" class.
Thanks!
Code:
public class Customer extends BaseEntity {
private String _salutation;
private String _phone;
private String _firstname;
private String _lastname;
private String _postcode;
private String _addressline1;
private String _addressline2;
private String _county;
private String _towncity;
private String _internalinfo;
private String _email;
private String _password;
private Card _card;
private Set _customerorders;
public Customer(){}
public void setCustomerorders(Set customerorders){
_customerorders = customerorders;
}
public Set getCustomerorders(){
return _customerorders;
}
public void setSalutation(String salutation){
_salutation = salutation;
}
public String getSalutation(){
return _salutation;
}
public void setPhone(String phone){
_phone = phone;
}
public String getPhone(){
return _phone;
}
public void setFirstname(String firstname){
_firstname = firstname;
}
public String getFirstname(){
return _firstname;
}
public void setLastname(String lastname){
_lastname = lastname;
}
public String getLastname(){
return _lastname;
}
public void setPostcode(String postcode){
_postcode = postcode;
}
public String getPostcode(){
return _postcode;
}
public void setAddressline1(String addressline1){
_addressline1 = addressline1;
}
public String getAddressline1(){
return _addressline1;
}
public void setAddressline2(String addressline2){
_addressline2 = addressline2;
}
public String getAddressline2(){
return _addressline2;
}
public void setCounty(String county){
_county = county;
}
public String getCounty(){
return _county;
}
public void setTowncity(String towncity){
_towncity = towncity;
}
public String getTowncity(){
return _towncity;
}
public void setInternalinfo(String internalinfo){
_internalinfo = internalinfo;
}
public String getInternalinfo(){
return _internalinfo;
}
public void setEmail(String email){
_email = email;
}
public String getEmail(){
return _email;
}
public void setPassword(String password){
_password = password;
}
public String getPassword(){
return _password;
}
public void setCard(Card card){
_card = card;
}
public Card getCard(){
return _card;
}
}
Customer.hbm.xml
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class name="uk.co.xiongmao.model.customer.Customer" table="customer">
<id name="id" type="int" column="id" unsaved-value="0">
<generator class="identity"/>
</id>
<property name="salutation">
<column name="salutation" sql-type="varchar(100)" not-null="false"/>
</property>
<property name="firstname">
<column name="firstname" sql-type="varchar(100)" not-null="false"/>
</property>
<property name="lastname">
<column name="lastname" sql-type="varchar(100)" not-null="false"/>
</property>
<property name="postcode">
<column name="postcode" sql-type="varchar(100)" not-null="false" />
</property>
<property name="addressline1">
<column name="addressline1" sql-type="varchar(100)" not-null="false" />
</property>
<property name="addressline2">
<column name="addressline2" sql-type="varchar(100)" not-null="false" />
</property>
<property name="county">
<column name="county" sql-type="varchar(100)" not-null="false" />
</property>
<property name="towncity">
<column name="towncity" sql-type="varchar(100)" not-null="false" />
</property>
<property name="internalinfo">
<column name="internalinfo" sql-type="varchar(100)" not-null="false" />
</property>
<property name="email">
<column name="email" sql-type="varchar(100)" not-null="false" />
</property>
<property name="password">
<column name="password" sql-type="varchar(100)" not-null="false" />
</property>
<!-- Here is the problem I believe -->
<one-to-one name="card" class="uk.co.xiongmao.model.customer.Card" />
<set name="customerorders">
<key column="customerorders"/>
<one-to-many class="uk.co.xiongmao.model.customer.CustomerOrder"/>
</set>
</class>
</hibernate-mapping>
Card.hbm.xml
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class name="uk.co.xiongmao.model.customer.Card" table="card">
<id name="id" type="int" column="id" unsaved-value="0">
<generator class="identity"/>
</id>
<property name="cardtype">
<column name="cardtype" sql-type="varchar(100)" not-null="false"/>
</property>
<property name="cardholdername">
<column name="cardholdername" sql-type="varchar(100)" not-null="false"/>
</property>
<property name="addressline1">
<column name="addressline1" sql-type="varchar(100)" not-null="false" />
</property>
<property name="addressline2">
<column name="addressline2" sql-type="varchar(100)" not-null="false" />
</property>
<property name="postcode">
<column name="postcode" sql-type="varchar(100)" not-null="false" />
</property>
<property name="county">
<column name="county" sql-type="varchar(100)" not-null="false" />
</property>
<property name="towncity">
<column name="towncity" sql-type="varchar(100)" not-null="false" />
</property>
<property name="fromdate">
<column name="fromdate" sql-type="datetime" not-null="false" />
</property>
<property name="expirydate">
<column name="expirydate" sql-type="datetime" not-null="false" />
</property>
<property name="issuenumber">
<column name="issuenumber" sql-type="int(11)" not-null="false" />
</property>
<property name="accountnumber">
<column name="accountnumber" sql-type="int(11)" not-null="false" />
</property>
<property name="securitycode">
<column name="securitycode" sql-type="int(11)" not-null="false" />
</property>
</class>
</hibernate-mapping>
CustomerOrder.hbm.xml
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class name="uk.co.xiongmao.model.customer.CustomerOrder" table="customerorder">
<id name="id" type="int" column="id" unsaved-value="0">
<generator class="identity"/>
</id>
<property name="orderdate">
<column name="orderdate" sql-type="datetime" />
</property>
<property name="customerdetails">
<column name="customerdetails" sql-type="varchar(100)" />
</property>
<property name="deliverycharge">
<column name="deliverycharge" sql-type="float" />
</property>
<property name="amount">
<column name="amount" sql-type="float" />
</property>
<property name="subtotal">
<column name="subtotal" sql-type="float" />
</property>
<set name="orderitems">
<key column="customerorder"/>
<one-to-many class="uk.co.xiongmao.model.customer.OrderItem"/>
</set>
<many-to-one column="orderstatus"
name="orderstatus"
class="uk.co.xiongmao.model.customer.OrderStatus"
not-null="false"/>
<many-to-one column="customer" name="customer"
class="uk.co.xiongmao.model.customer.Customer"
not-null="false"/>
<many-to-one column="card" name="card"
class="uk.co.xiongmao.model.customer.Card"
not-null="false"/>
<one-to-one name="discount" class="uk.co.xiongmao.model.customer.Discount" />
<one-to-one name="refund" class="uk.co.xiongmao.model.customer.Refund" />
</class>
</hibernate-mapping>
Application SQL
Code:
DROP DATABASE IF EXISTS `xmecs`;
CREATE DATABASE xmecs;
USE xmecs;
DROP TABLE IF EXISTS `menu`;
CREATE TABLE `menu` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(100) NOT NULL default '',
PRIMARY KEY(`id`)
) TYPE=MyISAM;
DROP TABLE IF EXISTS `category`;
CREATE TABLE `category` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(100) NOT NULL default '',
`code` int(11) NOT NULL default '0',
`menu` int(11) NOT NULL default '0',
PRIMARY KEY (`id`)
) TYPE=MyISAM;
DROP TABLE IF EXISTS `orderitem`;
CREATE TABLE `orderitem` (
`itemunit` int(11) NOT NULL default '0',
`customerorder` int(11) default '0',
`qty` int(11) NOT NULL default '0',
`id` int(11) NOT NULL auto_increment,
`unitprice` float NOT NULL default '0',
PRIMARY KEY (`id`)
) TYPE=MyISAM;
DROP TABLE IF EXISTS `orderstatus`;
CREATE TABLE `orderstatus` (
`id` int(11) NOT NULL default '0',
`name` varchar(20) NOT NULL default '',
PRIMARY KEY (`id`)
) TYPE=MyISAM;
INSERT INTO `orderstatus` (`id`,`name`) VALUES (1,'DECLINED PAYMENT'),(2,'APPROVED PAYMENT');
DROP TABLE IF EXISTS `itemunit`;
CREATE TABLE `itemunit` (
`id` int(11) NOT NULL auto_increment,
`code` int(11) NOT NULL default '',
`name` varchar(100) NOT NULL default '',
`description` varchar(200) NOT NULL default '',
`unitprice` float NOT NULL default '0',
`category` int(11) NOT NULL default '0',
PRIMARY KEY (`id`)
) TYPE=MyISAM;
DROP TABLE IF EXISTS `customer`;
CREATE TABLE `customer` (
`id` int(11) NOT NULL auto_increment,
`salutation` varchar(100) NOT NULL default '',
`firstname` varchar(100) NOT NULL default '',
`lastname` varchar(100) NOT NULL default '',
`postcode` varchar(100) NOT NULL default '',
`addressline1` varchar(100) NOT NULL default '',
`addressline2` varchar(100) NOT NULL default '',
`county` varchar(100) NOT NULL default '',
`towncity` varchar(100) NOT NULL default '',
`internalinfo` varchar(100) NOT NULL default '',
`email` varchar(100) NOT NULL default '',
`password` varchar(100) NOT NULL default '',
`card` int(11) NOT NULL default '0',
PRIMARY KEY (`id`)
) TYPE=MyISAM;
DROP TABLE IF EXISTS `card`;
CREATE TABLE `card` (
`id` int(11) NOT NULL auto_increment,
`cardtype` varchar(100) NOT NULL default '',
`securitycode` int(11) NOT NULL default '0',
`cardholdername` varchar(100) NOT NULL default '',
`issuenumber` int(11) NOT NULL default '0',
`accountnumber` int(11) NOT NULL default '0',
`fromdate` datetime NOT NULL default '0000-00-00 00:00:00',
`expirydate` datetime NOT NULL default '0000-00-00 00:00:00',
`postcode` varchar(100) NOT NULL default '',
`addressline1` varchar(100) NOT NULL default '',
`addressline2` varchar(100) NOT NULL default '',
`county` varchar(100) NOT NULL default '',
`towncity` varchar(100) NOT NULL default '',
PRIMARY KEY (`id`)
) TYPE=MyISAM;
DROP TABLE IF EXISTS `discount`;
CREATE TABLE `discount` (
`id` int(11) NOT NULL auto_increment,
`date` datetime NOT NULL default '0000-00-00 00:00:00',
`amount` float NOT NULL default '0',
PRIMARY KEY (`id`)
) TYPE=MyISAM;
DROP TABLE IF EXISTS `refund`;
CREATE TABLE `refund` (
`id` int(11) NOT NULL auto_increment,
`date` datetime NOT NULL default '0000-00-00 00:00:00',
`amount` float NOT NULL default '0',
PRIMARY KEY (`id`)
) TYPE=MyISAM;
DROP TABLE IF EXISTS `customerorder`;
CREATE TABLE `customerorder` (
`id` int(11) NOT NULL auto_increment,
`orderdate` datetime NOT NULL default '0000-00-00 00:00:00',
`customerdetails` varchar(100) NOT NULL default '',
`deliverycharge` float NOT NULL default '0',
`amount` float NOT NULL default '0',
`subtotal` float NOT NULL default '0',
`customer` int(11) NOT NULL default '0',
`card` int(11) NOT NULL default '0',
`discount` int(11) NOT NULL default '0',
`refund` int(11) NOT NULL default '0',
`orderstatus` int(11) NOT NULL default '0',
PRIMARY KEY (`id`)
) TYPE=MyISAM;