hibernate- adding to Set leads to InvocationTargetException
Taking my first steps with hibernate and postgres ,I created old style xml configurations for my entity classes and created some dao implementations as mentioned in( Manning Java Persistence with Hib) book and created a HibernateUtil class to create SessionFactory .To test these ,I created some entities and tried to save through dao .
In this code,Customer class has a set of 'Order's .To configure this I created the hbm.xml files as given below..
In the demo() method ,I created the entity instances and called saveOrUpdate() through dao. It runs successfully and creates the two customers and an order in db .However,when I try to add the order to a customer,it causes RuntimeException and rolls back the transaction. When I tried to debug the app,I found that
org.hibernate.context.ThreadLocalSessionContext.TransactionProtectionWrapper.invoke() ---> lang.reflect.Method.invoke() ---> java.lang.reflect.InvocationTargetException
I am confused why this occurs.This error wont occur if I don't call addOrdersToCustomers(). If I don't call that method,would it not mean the Customer object has no Set of orders?In the db,the Order table has a FK customer_id which is successfully set to the id of customer since createOrders() method sets the Customer field of Order to the customer instance.But,that doesn't make the Set orders field of Customer to be updated.
Any idea how to correct this? thanks,
Jim
public class Main {
CustomerDao custdao;
OrderDao orderdao;
Customer mark,jon;
Order order1,order2,order3;
Si开发者_运维百科mpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
public void demo()throws ParseException{
custdao = Daofactory.getCustomerDao();
orderdao = Daofactory.getOrderDao();
createCustomers();
createOrders();
//addOrdersToCustomers();//uncommenting this causes RuntimeException
updateEntities();
}
private void updateEntities() {
Transaction tx = null;
Session session = HibernateUtil.getCurrentSession();
logger.info("got session:"+session);
try{
tx = session.beginTransaction();
logger.info("got transaxion:"+tx);
custdao.saveOrUpdateCustomer(mark);
custdao.saveOrUpdateCustomer(jon);
orderdao.saveOrUpdateOrder(order1);
tx.commit();
}catch(Exception e){
tx.rollback();
}
}
private void addOrdersToCustomers() {
mark.getOrders().add(order1);
}
private void createCustomers() {
mark = new Customer();
mark.setName("mark");
mark.setEmailAddress("mark@home");
mark.setAddress("121,3rd avenue");
mark.setCity("San Diego");
mark.setState("CA");
mark.setCountry("U.S.A");
jon = new Customer();
jon.setName("jon");
jon.setEmailAddress("jon@home");
jon.setAddress("1121 vpura");
jon.setCity("bangalore");
jon.setState("karnataka");
jon.setCountry("india");
}
private void createOrders() throws ParseException {
order1 = new Order();
order1.setCustomer(mark);
order1.setOrderNumber(Long.parseLong("111111111"));
order1.setOrderDate(sdf.parse("2001/01/02"));
...
}
...
public static void main(String[] args) throws ParseException {
new Main().demo();
}
}
The mappings are as follows,
public class Customer {
private Long customer_id;
...
private Set<Order> orders;
public Customer() {
super();
orders = new HashSet<Order>();
}
...
}
<hibernate-mapping package="org.me.hibernatestore">
<class name="Customer" table="CUSTOMER">
<id column="CUSTOMER_ID" name="customer_id" type="java.lang.Long">
<generator class="native"/>
</id>
...
<set name="orders" table="ORDERS" lazy="false" cascade="delete-orphan">
<key column="CUSTOMER_ID"/>
<one-to-many class="Order" />
</set>
</class>
</hibernate-mapping>
Order.java
public class Order {
private Long order_id;
...
private Customer customer;
...
}
Order.hbm.xml
...
<class name="Order" table="ORDERS">
<id name="order_id" column="ORDER_ID" type="long">
<generator class="native"/>
</id>
...
<many-to-one name="customer" class="Customer" column="CUSTOMER_ID" lazy="false" />
...
The dao implementations have a base class
public class BaseDaoImpl<T, ID extends Serializable> implements BaseDao<T,ID>{
private Class<T> persistentClass;
private Session session;
public BaseDaoImpl() {
this.persistentClass = (Class<T>)(((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
}
public Session getSession() {
if (session == null){
return HibernateUtil.getCurrentSession();
}
return session;
}
...
}
HibernateUtil.java
public class HibernateUtil {
private static SessionFactory sessionFactory;
static {
try {
sessionFactory = new Configuration().configure().buildSessionFactory();
}catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static Session getCurrentSession(){
Session session = sessionFactory.getCurrentSession(); l
return session;
}
Your stacktrace clearly indicates the reason -- you're trying to save an object with a reference to a transient object. You either need to call save()
on your added Order
object before calling it on your Customer
, or you need to add an (at least) persist cascade on the orders
set in your Customer
class. In your xml case this would be correcting
<set name="orders" table="ORDERS" lazy="false" cascade="delete-orphan">
to
<set name="orders" table="ORDERS" lazy="false" cascade="delete-orphan,persist">
精彩评论