Hello
This is the first time that I'm using Hibernate and I've been having a lot of troubles getting as far as I'm now. I managed to fix all the issues I had so far by scouring the hibernate manual and all forums imaginable.
I have the following scenario:
I have a small app in which you should be able to manage customers and their bills. A customer has a one-to-many relationship with bills and bills in his turn has a one-to-many relationship with rules (multiple rules can be defined for a specific bill). I think my major issue is getting the tables to update properly but I think it might be due to my mapping.
My maps are:
Client.hbm.xmlCode:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="nl.webresource.jf.hibernate.model">
<class name="Client" table="Clients">
<id name="ClientID" column="ClientID" type="int">
<generator class="increment"></generator>
</id>
<property name="FirstName" column="FirstName" type="string"></property>
<property name="SurName" column="SurName" type="string"></property>
<property name="CompanyName" column="CompanyName" type="string"></property>
<property name="Street" column="Street" type="string"></property>
<property name="HouseNumber" column="HouseNumber" type="int"></property>
<property name="HouseNumberAddition" column="HouseNumberAddition" type="string"></property>
<property name="PostalCode" column="PostalCode" type="int"></property>
<property name="City" column="City" type="string"></property>
<property name="VatNR" column="VatNR" type="string"></property>
<property name="EmailAddress" column="EmailAddress" type="string"></property>
<property name="PhoneNumber" column="PhoneNumber" type="string"></property>
<property name="MobileNumber" column="MobileNumber" type="string"></property>
<property name="Inactive" column="Inactive" type="boolean"></property>
<list name="bills" table="Bills" inverse="true" lazy="false" fetch="subselect" cascade="all">
<key column="ClientID" not-null="true" update="false" />
<index column="BillID"/>
<one-to-many class="nl.webresource.jf.hibernate.model.Bill" />
</list>
</class>
</hibernate-mapping>
Bills.hbm.xmlCode:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="nl.webresource.jf.hibernate.model">
<class name="Bill" table="Bills">
<id name="BillID" column="BillID" type="int">
<generator class="increment"></generator>
</id>
<property name="ClientID" column="ClientID" type="int"></property>
<property name="BillDate" column="BillDate" type="date"></property>
<property name="Paid" column="Paid" type="boolean"></property>
<list name="rules" table="Rules" inverse="true" cascade="all,delete-orphan">
<key column="BillID" update="false" />
<list-index column="Position" />
<one-to-many class="nl.webresource.jf.hibernate.model.Rule" />
</list>
</class>
</hibernate-mapping>
Rule.hbm.xmlCode:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="nl.webresource.jf.hibernate.model">
<class name="Rule" table="Rules">
<id name="RuleID" column="RuleID" type="int">
<generator class="increment"></generator>
</id>
<property name="Name" column="Name" type="string"></property>
<property name="Price" column="Price" type="double"></property>
</class>
</hibernate-mapping>
I am using Dao's to insert/edit/delete records. I have a Dao for each table and they all implement abstractDao.
AbstractDao.javaCode:
public abstract class AbstractDao {
private Session session;
private Transaction tx;
public AbstractDao() {
try {
HibernateFactory.buildIfNeeded();
} catch(Exception e) {
System.out.println(e.getMessage());
}
}
protected void saveOrUpdate(Object obj) {
try {
startOperation();
session.saveOrUpdate(obj);
tx.commit();
} catch (HibernateException e) {
handleException(e);
} finally {
HibernateFactory.close(session);
}
}
protected void delete(Object obj) {
try {
startOperation();
session.delete(obj);
tx.commit();
} catch (HibernateException e) {
handleException(e);
} finally {
HibernateFactory.close(session);
}
}
protected Object find(Class clazz, int i) {
Object obj = null;
try {
startOperation();
obj = session.load(clazz, i);
tx.commit();
} catch (HibernateException e) {
handleException(e);
} finally {
//HibernateFactory.close(session);
}
return obj;
}
protected List findAll(Class clazz) {
List objects = null;
try {
startOperation();
Query query = session.createQuery("from " + clazz.getName());
objects = query.list();
tx.commit();
} catch (HibernateException e) {
handleException(e);
} finally {
HibernateFactory.close(session);
}
return objects;
}
protected List findAll(Class clazz, String condition) {
List objects = null;
try {
startOperation();
Query query = session.createQuery("from " + clazz.getName() + condition);
objects = query.list();
Hibernate.initialize(objects);
tx.commit();
} catch (HibernateException e) {
handleException(e);
} finally {
HibernateFactory.close(session);
}
return objects;
}
protected void findbla(Class clazz) {
HibernateFactory.sessionFactory.getClassMetadata(clazz).getPropertyNames();
}
protected void handleException(HibernateException e) throws DataAccessLayerException {
HibernateFactory.rollback(tx);
throw new DataAccessLayerException(e);
}
protected void startOperation() throws HibernateException {
session = HibernateFactory.openSession();
tx = session.beginTransaction();
}
}
All other Dao.java files are the same except for the argumentsCode:
package nl.webresource.jf.hibernate.dao;
import nl.webresource.jf.hibernate.model.Client;
import java.util.List;
public class ClientDao extends AbstractDao {
public ClientDao() {
super();
}
/**
* Insert a new Client into the database.
* @param event
*/
public void create(Client client) throws DataAccessLayerException {
super.saveOrUpdate(client);
}
/**
* Delete a detached Client from the database.
* @param client
*/
public void delete(Client client) throws DataAccessLayerException {
super.delete(client);
}
/**
* Find an Client by its primary key.
* @param i
* @return
*/
public Client find(int i) throws DataAccessLayerException {
return (Client) super.find(Client.class, i);
}
/**
* Updates the state of a detached Client.
*
* @param client
*/
public void update(Client client) throws DataAccessLayerException {
super.saveOrUpdate(client);
}
/**
* Finds all Clients in the database.
* @return
*/
public List findAll() throws DataAccessLayerException{
return super.findAll(Client.class);
}
public List findAll(String condition) throws DataAccessLayerException{
return super.findAll(Client.class, condition);
}
}
So far I've got everything to work except deleting a client just after adding a bill! I think my problem started with the mapping of the list. At first I was using lazy="true" but that threw the LazyInitializationException when I tried to use the getBills().size() function on one of the clients. After digging through the manual I changed the lazy="false" and started using that in combination with fetch="subselect". That worked pretty well until I added about 5+ clients. It slowed everything down so I figured that wasn't the way to go..
Basically I am trying to get the following scenario:
Whenever I add a bill it should (somehow) update the entry in the Client table so that when I try to delete the client immediatly after adding a bill it would correctly fetch the amount of bills a certain user has (through c.getBills().size()). I tried removing the client from the tablemodel's list and then adding it again but that ended up with 2 of the same records for that client. For some reason it wasn't deleting it properly. Maybe because the client instance changed due to the new bill being added..
I was hoping that someone could point me in the right direction because my hands are pretty tied right now and I've been trying to get this to work for a few days now... I've tried so many different mapping settings but none seem to give the correct effect.
I was thinking about the following scenario:
When a user is set for deletion (toolbar button) it should first check if that user has any Bills in the system. If that's true the user should be set to inactive by defining the Inactive column to true. That part does the trick! However if I have both tables open and I try to add a bill and then immediatly switch tabs without reloading the application, upon deletion of the Client it says there are 0 bills.. Thus it deletes the client. That is ofcourse not what is suppose to happen. I am quite sure that it is due to data inconsistency because the Client instance in the Clients JTable doesn't get updated correctly..
Hopefully I've made myself a bit clear. If I have missed any source code please let me know so I can post it.
Thanks in advance!