At its core, the Data Layer’s main purpose is:
Data Layer’s Main Purpose:
To abstract all interactions with the database so that business objects can be written to deal with business rules, not with database interaction.
For example, when promoting a standard Deal, the business logic comprises:
- validate that the Deal is in a promotable state
- promote the Deal
- generate the related Deal Transactions
- generate the related Confirmation
In addition to these items, there are interactions with the Deal Pricing, Deal Costing, Deal Transaction Pricing and a variety of other lookup tables. Records need to be saved, retrieved, updated and deleted to facilitate the persistence of the Deal’s new “Promoted” state. The Data Layer will encapsulate the code that interacts with the database, so the Deal Promoter class only needs to be concerned with the business rules of promoting a deal, and not with the mechanics of persisting those changes to the database.
In order to effectively serve as an Object-Relational Mapping (ORM) tool, the Data Layer needs to implement the following principles.
Principle 1: The Data Layer should generate the code necessary to deal with different tables and should provide a common API for working with the resulting data objects.
A typical database interaction involves the following steps:
- Get the connection string
- Open the connection
- Create the command object
- Execute the command
- Close the connection
The only thing that changes from table to table is the names of the table and its columns. All of the database code is identical.
Principle 2: The Data Layer should be able to work with the entire Object Graph by saving and retrieving related objects as a set.
Some objects are more complex than others, for example, a Deal has Pricing, Charges and Transactions that are an integral part of it. It also has Confirmations that are related to it. When saving a Deal, the pieces and parts of the Deal should get saved too.
Principle 3: The Data Layer should handle failures within the context of a transaction and roll back the changes to a consistent, stable state.
Sometimes, when saving a complex object, an error may occur in one of the pieces. In this case, the Data Layer should gracefully handle the error and leave the object and the database in a stable, consistent state.
Principle 4: The Data Layer should intelligently map database tables to appropriate Business Objects.
In several cases, a business object will represent a concept differently than the database might. For example, the database table EMPLOYEE contains all the records for the Employees, Managers and Direct Reports business classes.
Principle 5: The Data Layer should handle concurrency properly.
When objects are saved to the database, concurrency problems arise because the data being saved is about to overwrite data that has already changed since it was last retrieved. Concurrency resolutions include: Overwrite, Merge and Discard. The Data Layer needs to support these options and allow developers to choose which resolution to employ.
Principle 6: The Data Layer should support LINQ.
In order to provide data sources for drop downs and grids the Data Layer needs to be able to support querying, including sorting, grouping and summarizing. There are three choices to do this:
1) Oracle native SQL queries
Implementing this technique often pushes Business and UI logic all the way back into the database. It makes ORM a challenge as the query objects are not like table-based as they are not updateable and do not usually have the necessary key fields.
2) Custom querying support in the Data Layer
Implementing this technique is complex, non-standard and may have performance issues.
3) LINQ (The .Net framework’s built in query language)
Implementing LINQ provides powerful, sophisticated, query capabilities. LINQ to Entities also raises performance by taking advantage of the Entity Framework’s knowledge of the database objects.
Principle 7: The Data Layer should support asynchronous communication.
One of the worst aspects of application performance is the perceived lag while waiting for data to be retrieved from a database, transferred over the network and rendered in the UI. Asynchronous communication is the recommended way to prevent this lag by allowing the UI to be responsive while the data is retrieved, transferred, and even rendered, asynchronously. In Silverlight, all network communication is asynchronous, so the Data Layer must support asynchronous communication.
Principle 8: The Data Layer should support Oracle specific features, such as Sequences, Packages and Oracle Data Types.
Most Oracle tables have a key field that is a numeric tied to a Sequence value. Much of the legacy code is embedded in the Database in Oracle Packages. There are also some Oracle specific Data Types (particularly LOB’s) that need to be translated to/from their .Net equivalents. The Data Layer needs to handle all three of these situations properly.
Trouble Shooting Support
Principle 9: The Data Layer should support granular logging for debugging and troubleshooting.
When debugging and troubleshooting, a detailed log of what is happening can be a very useful tool. Especially in asynchronous or Inversion of Control situations where the code cannot be easily stepped through, a log is critical to the discovery and elimination of bugs.
Principle 10: The Data Layer should support server-side and client-side caching to improve performance.
Data Caching on the Server-side allows redundant calls for data from different clients to be served in a single database request. Data Caching on the Client-side allows redundant calls for data on the client to be served on the client without any network traffic at all.
Principle 11: The Data Layer should support validation at the client and at the server to improve performance.
Eliminating round trips by providing client-side validation will improve performance. Providing server-side validation will ensure data integrity at the server.