Context
Programmers use object-oriented concepts to model real-world entities in a natural, familiar way. An object's behavior enables it to interact with other objects using application domain semantics. Domain objects related by aggregation and inheritance collaborate to implement elegant application-level solutions.
When it comes time to read or write the relational data that domain objects represent, an application's elegance often suffers. This happens because it is usually not possible to directly model the real world with relational data. Instead, you must morph real-world entities into a row and column format. This format sharply contrasts with the versatility that object-oriented models provide.
For example, consider some of the objects involved in an order processing application. An order is made up of a unique order identifier, the identifier of the customer who placed the order, the date that the customer placed the order, and a collection of zero or more line items that make up the order. Similarly, a line item consists of a line item identifier, a product identifier, the quantity that the customer ordered, and the product's unit price. Figure 3.1 illustrates the Order and LineItem classes that define domain objects for this application:

The data model includes ORDERS and LINE_ITEMS tables that define similar concepts, although the relationship between these tables is not so straightforward. Figure 3.2 illustrates these tables. Since a single order contains zero or more line items, there is a one-to-many relationship between rows in the ORDERS table and those in the LINE_ITEMS table. To associate rows across these tables, LINE_ITEMS defines the ORDER_ID column as a foreign key (FK) that you can use to join with the ORDERS table.

Consider a simple business process that the application must perform. It carries out the following tasks to generate order invoices:
Determine the appropriate queries—
The application queries the ORDERS and LINE_ITEMS tables to gather all the information it needs to generate order invoices. This may entail a single join operation across both tables, or it may require multiple queries involving the individual tables.
Issue the queries—
The application initializes a database connection if one is not already available and interacts directly with the database driver to issue the queries.
Parse the query results—
The application reads the data from the query results and organizes it by creating Order and LineItem object representations. This may also require converting data from its database format to a format more amenable to the application's semantics.
Print the invoices—
The application uses the Order and LineItem objects to iterate through all the orders, calculate total prices, and print the invoices.
The first step requires tight coupling between the application and the data model, since the application forms the queries. Similarly, the second and third steps couple the application with data access code, in this case, the database driver and its resources.
The Object/Relational Map pattern decouples both the data model and data access details from an application and its domain objects. The mapping between object-oriented concepts and relational data becomes the responsibility of a separate component, allowing it to be changed independently of the application and domain objects. An object/relational map is commonly defined using an abstraction that hides all of its mapping details from applications. Figure 3.3 illustrates how the object/relational map abstraction and implementation achieve this decoupling:

The object/relational map implementation is responsible for the mapping between domain objects and relational data and usually interacts directly with a physical database driver. One option is to define a custom implementation that hardwires all the mapping details for a single domain object, application, or system. Hardwiring these details in code makes it less amenable to changes, but it provides a cleaner decoupling than burying the same mapping within application code or domain objects. It may also be an effective prototyping strategy that allows you to develop applications before you build a more versatile solution.
Sophisticated object/relational map systems define mapping details using metadata. Metadata makes an implementation quite versatile, since you can change the mapping details without updating or recompiling application or domain object code. It is common to store mapping metadata in configuration files or a database. It is also common to define administration tools that allow users to view and update mapping details without having to understand the persistent metadata format.
The most fundamental issues that an object/relational map system deals with are how to map object-oriented concepts to relational database concepts. Table 3.1 describes a common analogy. These are general guidelines and are not required. You can define a class for each table that your application uses. The application or object/relational map instantiates object instances for each row as it referencse the rows. Each domain object exposes analogous column values as attributes.
In practice, these are not always direct correspondences. For example, an object/relational map often hides relational data that an application does not need, such as keys used purely for defining table relationships or identity attributes. In addition, the object/relational map can convert data in both directions and calculate attributes on behalf of the application, encapsulating even more details of the data model. If you need to define domain objects that stray further from this analogy, you must ensure that the object/relational map system that you choose supports the mapping capabilities you require.
Table 3.1. A Common Analogy for Mapping Between Object-Oriented and Relational Database|
Class | Table | Object | Row | Attribute | Column |
With an object/relational map in place, the steps for generating invoices within the order processing application become much easier to describe:
Request the orders—
The application requests relevant orders and the object/relational map returns them as a collection of Order objects.
Get each order's line items—
These are available directly from the Order object. Remember that in object-oriented terms, an Order contains a collection of LineItems and the Order class exposes the collection as one of its attributes.
Calculate and report—
Calculate totals and print the invoice as before.
Notice that the application operates exclusively using domain objects and makes no explicit reference to the relational data model or data access. The same physical data access operations happen as did with the coupled approach described earlier, but this time, the object/relational map issues them transparently.
Implementing an object/relational map that handles simple cases like the order processing application requires is a reasonable undertaking. However, if you plan to make extensive use of object/relational mapping within your applications, you probably do not want to tackle creating a generic implementation from scratch. Writing an efficient, versatile, and metadata-driven object/relational map is a difficult task. Fortunately, there are many commercial products and standards available that you can employ directly within your application. Most of these products allow you to define map metadata using tools or configuration files and plug in a variety of database drivers for physical data access.
 |