Hi,
After weeks of trying to design my system to use Spring and Hibernate with not really satisfying result, I start to believe my design isn't to good + lack of understanding Hibernate/Spring properly(?).
Well, here's a brief description of my domain.
My system is based on one, sat it again,
one complex object coposed by ~40-50 other objects. Let's say it's a car, a car is build on screws and bults etc. Almost every object have bi-directional associations, seldom any many-to-many relationships.
This system should be design so it can easily adopt to J2EE and EJB's. I'd really like to develop all my dao objects, business object so they easily could be wrapped around a EJB.
The system should be developed in a layered architecture, well a logical 3-tier 'cause well be running the system with POJO's as 2-tier, and J2EE as 3-tiered.
By logical 3-tier I mean that well try to program all of the objects as they really should be distributed in a 3-tiered architectured, even though they are going to be part of the 2-tier architecture with POJO's.
My different layers is:
Code:
* Presentation - Contains all UI related classes
* Middle - Should contain very well defined interfaces towards the business layer, for transaparent access to EJB's
or POJO's.
* Business - Contains all of our business objects
* Integration - Our DAO objects tec.
One argument for using Spring framework together with Hibernate is the transaction management. There exists a requirement that the system should be able to migrate to using JDO in the future. Spring provides a very nice IoC management for changing from HibernateTransaction to JDOTransactions to JTATransactiosn etc.
Today we've made a very narrow business interface for managing our complex object, the car. It's just contains methods to:
NOTE! All of these methods uses Spring transaction management.
Code:
public Car createNewCar(Car newCar);
public Car updateCar(Car carToUpdate);
public Car loadCarById(Object carId);
public Car addCarComponent(CarComponent newCarComponent);
public void deleteCarComponent(Car carComponentToDelete);
Because of the complex object is composed of ~40-50 other objects we don't want to have 40-50 business objects or CRUD method cluttering the interface, this is something I need suggestions on!!!
The methods
addCarComponent() and
deleteCarComponent() uses reflection to find out what kind of component we'd want to add/delete. By reflection we're locating it's data access object (one dao per entity object) and performs the relevant operation (
sessionsave() or
session.delete()) in the current dao.
All session management is handled in the integration layer, so there's not possible to flush a session explicitly between two CRUD operations, inside a business method, that is invoked in one transaction (if not the
session.flush() is exposed by my dao's).
I'll describe some of my use-cases:
Code:
1. Create a new car; the minimal car components is created and persisted to db. The minimal amount of the car components
is created and assembled in the UI, the the whole Car object is sent down to the business method createNewCar().
The persisted Car object is then returned to the UI.
2. Persist updated car. We've made some changes (not added or removed any objects)
to the Car object in UI and like to persist the changes: updateCar() is invoked
3. We'd like to delete a car component from the Car object.
The CarComponent we'd like to delete is sent down to the business
layer.
The changing of serialnumbers is happening in both delete/add business methods:
NOTE! These steps is performed inside the business method, in one single transaction.
3.1 The deleted objects changes some serialnumbers of it's related
objects. This is possible due to bi-directional associations.
This object we're deleting fetches it's parent and gets its "siblings",
changes their serialnumbers etc.
3.2 Due to the bi-directional associations we can get a reference to the
topmost Car object. A updateCar() is invoked on this car components
topmost parent Car object.
3.3 All of the associations to the object we're deleting is removed.
3.4 The object is sent to its dao and a sessiondelete() on that object
is performed. (Normally it's here a "cascade during flush" is issued).
4. We'd like to add a new car component to the Car object.
The new CarComponent is sent to the business method addCarComponent()
4.1 Changes to the existing Car objectsa serialnumber is made.
4.2 Business method updateCar() is invoked.
4.3 session.save() on my car component is invoked in its dao
Often due to my cascade setting and my complex data modell I get problems like "flush during cascade is dangerous" or "not-null constraint violations".
Maybe there is easier to have sperate methods for saving CarComponents due to the complex cascade hierarchy that otherwised should be managed when only for example
updateCar() is available?
I'd like someone to share some comments on the above described approach. Tell me what could be solved a better way, simplier way etc. I'm dying to learn!
Kindest regards, Andreas