Re: Question regarding OOP and database access
- From: "H. S. Lahman" <h.lahman@xxxxxxxxxxx>
- Date: Wed, 06 Jul 2005 17:28:52 GMT
Responding to Leodippolito...
My problem: if the Wheel table changes in the database, I have wheel-related SQL code spread all over different DB layers (those DB layers that 'join' with the wheel table). For example, the Truck DB layer. If this happens I would have to track where I have these joins and modify the sql code.
Isolate everything related to accessing the RDB into a single subsystem or layer. That layer has semantics for things like Schema, Dataset, Table, and Tuple. The paradigm for talking to the RDB itself is SQL queries. Note that the semantics of Car, Wheel, etc. is not relevant in this subject matter. That semantics is represented purely in terms of identity for the instances.
OTOH, your business problem does not care whether your data is stored in an RDB, an OODB, flat files, or crop circles. The semantics are pure business semantics like Car, Truck, and Wheel. You want that logic to be completely independent of the semantics of storage mechanisms so you don't want anything remotely resembling a SQL query polluting your business logic.
Separate the subject matters with subsystem interfaces that are message-based and pure by-value data transfer. That decouples to two disparate views of semantics. Then all you need to do is encode/decode message data packets on each side of the boundary. Of course each side needs its own view of identity for the data packets. That view may be 1:1 for simple situations or it may be more complex (e.g., an object on the business side is an amalgam of data from two tables combined via a join on the RDB access side).
Let the DB access subsystem/layer provide the mapping of interface identity to tables via joins and whatnot. Because schemas, joins, and whatnot can be expressed in terms of data, if you get clever about the DB access the same subsystem can be reused across applications by simply modifying the configuration data that maps identity to the RDB.
I could solve this by making the DB layers touch only data related to the object (Car DB layer access only Car table and Wheel DB layer access only Wheel table), and making different trips in the business layer to build the object:
// CAR BUSINESS LAYER
public Car getCarById(int p_id) { CarDataLayer carDB = new CarDataLayer(); Car objCar = carDB.getCarById(p_id);
WheelDataLayer wheelDB = new WheelDataLayer(); Wheel objWheel = wheelDB.getWheelById(objCar.aWheel.ID);
objCar.aWheel = objWheel;
return objCar; }
This is basically the right idea. This is the sort of code one would have in a factory object that creates a Car instance. (You probably want to create both the Car and Wheel instances in the same method scope to ensure data and referential integrity.) However, rather than having distinct carDB and wheelDB interfaces, you can do something more generic like (I'm not sure what language you are using, so I'll use C++),
public Car CarFactory::getWholeCarByID(in p_id)
{
WholeCarDataSet* ds;
Car* car;
Wheel* wheel;ds = DBAccess.getWholeCar(p_id); // get data from DB
wheel = new Wheel (ds.wheelID, ds.wheelSize, ...)
car = new Car (p_id, wheel, ds.carModel, ...)
// the wheel reference is used to instantiate the relationship
// between Car and Wheel.return car; }
Here WholeCarDataSet is an aggregate of all the data obtained from the DB related to a Car and its Wheels. In effect it just maps a by-value data packet. That data packet is loaded by the DB access subsystem/layer in response to the getWholeCar(p_id) request. The DB access subsystem knows that for this request it requires a particular join between the Car and Wheel tables.
Note that the CarFactory needs to know nothing about how the data is stored or organized. It just asks for what /it/ needs, which is all the data related to a whole Car with a particular ID. It relies on the DB access subsystem to get it so all it has to do is pick the data out of the returned data packet.
This way, if the Wheel table changes I am ok with the sql code. I don't need to track anything in DB layers. If I ask for a car or truck object, it will return a car or truck with the new-version wheel.
Exactly. In addition, in my version you don't even depend on the DB recognizing Car and Wheel as separate database entities (tables).
The cost of this is the n-round-trips that I have to make to the DB layer in the business layer. I lose the power of SQL join.
The SQL join is still there. It is just fully encapsulated in the DB access subsystem. An obvious application-specific way to address that is to have a set of Query subclasses, one for each pile of data the business layer needs. Then the Query instance knows how to formulate its SQL query and pack its dataset. Then the getWholeCar interface method just dispatches to the right Query instance.
The next step is to realize that the SQL join string for each unique Query can be stored externally and read in at startup to create the Query instances. Now the only application-specific thing is the packing of the data set for the request return. That's a bit more complicated but it can also be specified parametrically using external data. [My blog has some examples in the category on persistence.] At that point, as I indicated above, the access layer no longer has encoded business semantics (it is now all in the configuration data) so it can be reuse as-is across applications.
Bottom line, if you have multiple applications that access DB, you should be able to engineer that access once (albeit at a somewhat higher cost than for a single application).
************* There is nothing wrong with me that could not be cured by a capful of Drano.
H. S. Lahman hsl@xxxxxxxxxxxxxxxxx Pathfinder Solutions -- Put MDA to Work http://www.pathfindermda.com blog: http://pathfinderpeople.blogs.com/hslahman (888)OOA-PATH
.
- References:
- Question regarding OOP and database access
- From: leodippolito
- Question regarding OOP and database access
- Prev by Date: Re: OOP/OOD Philosophy
- Next by Date: Re: OOP/OOD Philosophy
- Previous by thread: Re: Question regarding OOP and database access
- Next by thread: Re: Question regarding OOP and database access
- Index(es):
Relevant Pages
|