|
|
| Home > .NET > Database |
|
Top 10 features for using an O/R mapping tool
Posted by
Iqbal Khan
on
Monday, November 07, 2005 (EST)
In this article, I will try to educate you about the various important features that a good O/R mapping tool would provide you and how it can be beneficial to you. I am not discussing any particular O/R mapping tool but rather all tools in general.
This article has been viewed:
3,024
times
Technology:
Database.
|
Contents
O/R mapping tools are becoming more popular each day and people are realizing the
productivity gain they provide to developers. Yet, many people don’t know enough
about O/R mapping to consider using these tools and many others are weary of using
any code generators (including O/R mapping tools).
In this article, I will try to educate you about the various important features
that a good O/R mapping tool would provide you and how it can be beneficial to you.
I am not discussing any particular O/R mapping tool but rather all tools in general.
What is O/R mapping?
If you’re developing an object oriented application that requires a relational database,
you’ll need to develop persistence objects that are modeled against your database
design and know how to interact with different tables in the database. You can either
develop these objects by hand or use an O/R mapping tool to map and generate them
quickly. Hopefully, after reading this article, you’ll be convinced that developing
by-hand is a bad idea in most situations.
An O/R mapping tool connects to your database and reads its schema, then lets you
map persistence objects to database tables and views, specify single-row transactional
operations, queries, and stored procedure calls as methods to these objects. And,
it also lets you define one-to-one, one-to-many, many-to-one, and many-to-many relationships
between objects based on relationships in the database. It then generates fully
working persistence objects code for you. Below is a simple example of some persistence
objects. Please note that in this persistence design pattern as explained in Domain
Objects Persistence Pattern for .NET, the persistence objects are broken up into
"Domain Objects" and "Factory Objects". You can read more about this design pattern
if you wish.
CREATE TABLE t_employees (
employee_id int IDENTITY (1, 1) NOT NULL,
name nvarchar (40) NOT NULL,
birth_date datetime NULL,
photo image NULL,
reports_to int NULL,
)
// Domain object class for t_employees table
public class Employee
{
Int32 _employeeId;
String _name;
DateTime _birthDate;
Byte[] _photo;
Int32 _reportsTo;
ArrayList _subordinates;
Employee _supervisor;
Int32 EmployeeId {
get { return _employeeId;} set { _employeeId = value; }
}
String Name {
get { return _name; } set { _name = value; }
}
DateTime BirthDate {
get { return _birthDate; } set { _birthDate = value; }
}
Byte[] Photo {
get { return _photo; } set { _photo = value; }
}
Int32 ReportsTo {
get { return _reportsTo; } set { _reportsTo = value; }
}
ArrayList Subordinates {
get { return _subordinates; } set { _subordinates = value; }
}
Employee Supervisor {
get { return _employee; } set { _employee = value; }
}
}
// Persistence object for Employee class
public interface IEmployeeFactory
{
void Load(Employee object, int nDepth);
void Insert(Employee object);
void Update(Employee object);
void Delete(Employee object);
// Query methods
ArrayList FindSomeEmployees();
// Relationship methods
void LoadSupervisor ( Employee emp);
void LoadSubordinates(Employee emp, int nDepth);
}
Below is an example of how a client application will use this code:
public class NorthwindApp
{
static void Main (string[] args) {
Employee emp = new Employee();
EmployeeFactory empFactory = new EmployeeFactory();
// Let's load a employee from Northwind database.
emp.EmployeeId = 10045;
empFactory.load(emp);
// empList is a collection of Employee objects
ArrayList empList = empFactory.FindSomeEmployees();
// subList is a collection of Employee's subordinates objects
ArrayList subList = empFactory.LoadSubordinates(emp, 1);
// supervisor is Employee's supervisor object
Employee supervisor = empFactory.LoadSupervisor(emp);
}
}
Top  Feature 1: Flexible object mapping
Everything in O/R mapping starts with mapping your objects to your relational
tables. Here are some specific features in this area that you should know:
- Tables & views mapping: The tool should let you map objects to both
tables and views in
your relational database. Mapping to views is important because many real-life
applications prefer to use views instead of tables.
- Multi-table mapping: The tool should let you map an object not only
to a single table but
also to multiple tables and specify a join between these tables. If your application
needs to fetch list of rows that span multiple tables (a common occurrence in
web applications), you’ll need this feature.
- Naming convention: The tool should let you use a different naming
convention in objects and their attributes than in relational databases. If
your database table is named t_employees, your object may need to be named Employee.
- Attribute mapping: There are a number of features that the tool should
support:
- Primary key: Your object must distinguish the primary key from
other columns. It should also let you use a single-column or multi-column
primary key.
- Auto generated columns: Some columns are auto generated (IDENTITY
or SEQUENCE) and your object must have code to handle fetching the generated
values after an insert.
- Read-only columns: Some columns are not meant to be set by the
client but instead their values are system generated (e.g. creation_dtime
column using getDate() function in SQL Server). Your object must have appropriate
code to fetch these system-generated values.
- Required columns: Your object must do data validation for required
columns at the time of insert or update operations. This is much more efficient
than wasting a trip to the database just to get an error message back.
- Validation: In most cases, you have defined various constraints
on your database columns. It would be nice to have the same validations
done in your persistence objects so you can save an unnecessary trip to
the database just to receive an error message.
- Formula Fields: There are many situations where when you
fetch data from the database, you use a regular expression rather than a
column (e.g. Annual Salary object attribute might be a formula field monthly_salary
* 12).
- Data type mapping: Sometime, you want to map one data type from
the database to another data type in your object. For example, a datetime
type might be converted into a string. Your object must have the logic to
do this automatically in both directions (read and write).
Top  Feature 2: Use your existing domain objects
As you saw, a popular design pattern separates persistence objects into “domain”
and “factory” objects. One important O/R mapping feature is to let you decide whether
you want to generate both domain and factory objects or use your existing domain
objects and only generate factory objects that know about your domain objects.
Some people do not want to generate “domain” objects and instead develop them by
hand and only generate the “factory” objects. The reason behind this is that their
domain objects are being used in almost all subsystems of their application and
therefore they don’t want them changing frequently through subsequent code regenerations.
But, they don’t mind generating the “factory” objects since their use is localized
to a few places (for load and save operations).
Therefore, the O/R mapping tool should let you use your existing domain objects
and map and generate only the factory objects. It should use .NET Reflection to
read your domain object definition and after you have done the mapping, it should
generate the factory objects in such a way that these factory objects use your domain
objects to hold all the data.
Top  Feature 3: Transactional operations (CRUD)
A database transaction allows you to group multiple operations as one atomic operation
so either all operations succeed or none of them succeed. Transactional operations
include create, read, update, and delete (also called insert, update, load, and
delete). Each transaction operation is performed only on one row of data in a table.
You’ll be working in one of two main transactional environments and your O/R mapping
tools needs to know both of them so it can generate code accordingly. They options
are:
- COM+/MTS: Microsoft Transaction Server (MTS) manages all transactions
of an application. Your objects do not start, commit, or rollback a transaction.
They only return success or failure from their methods and MTS figures out when
to do “BeginTrans”, “Commit”, or “Rollback”. Additionally, all your factory
objects are stateless so MTS can do object pooling on them. This is a specific
design pattern that your O/R mapping tool must understand and generate your
persistence objects to comply with it. Most common applications for this environment
are ASP.NET applications and .NET Web Services.
- Stand-alone: This is the environment where your application manages
all the transactions itself. It needs to know where to go “BeginTrans”, “Commit”,
and “Rollback”. And, your O/R mapping tool needs to be aware of this environment
and generate code to comply with it. Most common situations for this are Windows
Forms based client/server applications that directly talk to the database server.
Top  Feature 4: Relationships and life cycle management
The foundation of a relational database is that tables have relationships with other
tables. Similarly, when you map objects to these tables, your objects also need
to establish the same relationships with other mapped objects. Therefore, your O/R
mapping tool must support this very important feature by letting you determine which
relationships you want to keep in your objects. Below are the different types of
relationships you must have:
- One-to-one relationship: In this, your object must contain a reference
to exactly one other object and must handle load and save scenarios for it.
- Many-to-one relationship: This is very similar to one-to-one where
your object must contain a reference to exactly one other object and must handle
load and save scenarios.
- One-to-many relationship: In this, your object must contain a collection
of the related objects and must handle loading them with load and also adding
and removing them with save operations.
- Many-to-many relationship: This is the most complex relationship
and involves a bridge table in the database to establish the relationship. There
are two different situations for the bridge table as described below:
- Bridge table with only primary key: In this situation, the bridge
table contains only the primary key (which is actually composed of multiple
foreign keys). So, your object need not have any bridge table attributes
and only needs to keep a collection of the related objects (similar to one-to-many).
In fact, the public interface of your object is usually identical to one-to-many
but the underlying code is different because of the bridge table.
- Bridge table with additional columns: This is the most complex
situation because the bridge table has additional useful columns that your
object must cater for. Your object needs to load a collection of composite
objects containing both the bridge table and the related table information.
The life cycle management feature must include the ability to load a primary
(or parent) object and through this object load all the related objects
(meaning all the different relationships). You should also be able to add
newly created related objects or remove existing related objects from the
relationships. And, when you save the primary object, it must save all the
relationship information along with it (as one transaction). A good O/R
mapping tool would let you define all types of relationships and also handle
life cycle management in the generated code.
Top  Feature 5: Object inheritance
As you already know, a very important aspect of object-oriented programming
is inheritance. However, relational databases do not automatically provide inheritance
in the relational model. But, there are a number of patterns on how to map object
inheritance to a relational database. And, a good O/R mapping tool must provide
this capability.
Here are a few ways in which object inheritance is mapped to relational databases.
- One table per object: This is the most popular and flexible pattern.
In this, each object is mapped to its own table in the database. And, there
is a one-to-one relationship between every base object and its derived object.
The foreign key of this relationship is kept in the derived object. It is the
most flexible because without changing the structure of any existing tables,
we can keep adding to the inheritance hierarchy. However, it is not the most
efficient for loading both base and derived objects because a separate “load”
is done for each object.
- One table for all objects: In this pattern, the base object and all
the derived objects are represented in one table in the database. This table
contains columns representing attributes from all the objects. It is the most
efficient for loading and saving data but is very limited because adding a new
object to the inheritance requires changing the structure of an existing table
in the database that is highly undesirable.
Keeping this in mind, the O/R mapping tool must support at least the “One table
per object” approach and if it can also support the second approach that is
icing on the cake. The generated code for base and derived classes should handle
the following situations:
- Insert and update operations: The derived class must first ask
the base class to do Insert or Update and then do its own. But both the
base and derived class operations must be performed in one transaction.
- Delete operation: Unlike the insert and update operations, the
delete operation is performed first on the derived object and then on the
base object. However, both must be done in one transaction.
- Load operation: The load operation in the derived class must
also call load on the base class and both of these should be done in one
transaction.
Top  Feature 6: Static and dynamic queries
The next most common thing that a database application does is to retrieve rows
of data from one or more tables. The application does this done by using SQL queries
(SELECT statements). However, an object-oriented application wants to fetch a collection
of objects and not rows. So, the O/R mapping tool must provide a way for you to
create queries that return collections of objects.
Static queries are those that are defined at compile time and the only thing that
changes at runtime for them are the parameter values. These queries can be precompiled
and run very efficiently. So, the O/R mapping tool must allow you to define static
queries as methods of your objects and also specify whether these queries take any
run-time parameters or not.
Dynamic queries on the other hand are those where either the query or its criteria
is created at runtime. These queries cannot be precompiled and must run as “Dynamic
SQL”. However, the benefit of these queries is that they allow those situations
in your application where you’re performing ad hoc search operations and based on
the user input you determine what the query should look like. These queries need
to also be provided as methods to your objects but with the flexibility that you
can specify the “WHERE clause” and “ORDER BY clause” at run-time.
Top  Feature 7: Stored procedure calls
Stored procedures have become very popular in high transaction environments because
they allow you to put all your SQL inside the DBMS and in a compiled form. As a
result, your SQL does not have to be compiled at runtime because that is a very
expensive process. There are two situations that an O/R mapping tool must support
when it comes to stored procedures as described below:
- Existing Stored Procedures: First is when you already have custom
stored procedures in the DBMS and you want to have your persistence objects
call them. In this situation, the O/R mapping tool must allow you to define
methods in your objects that can call stored procedures. It must also support
different parameter types (in, out, in/out) and also whether the stored procedure
returns a Recordset or not. If the stored procedure returns a Recordset then
the object must return this data to its client.
- Generate Stored Procedures: The second situation is where all the
SQL (minus the dynamic queries) that is going to be generated as a result of
your object-relational mapping is put inside the DBMS as stored procedures and
your objects code is generated so it calls these stored procedures. If you didn’t
generate stored procedures for all the SQL, it would be put inside your object
source code as “dynamic SQL”.
Top  Feature 8: Object caching
If your application is transaction intensive and supports high traffic, you really
cannot live without effective caching built into your application. Microsoft provides
ASP.NET Cache object but it is not sufficient for clustered environments where your
application is running on multiple servers and needs a cache that is also clustered.
However, there are commercial caching solutions available in .NET that cater for
clustered environments.
Whichever caching product you use, you’ll have to make sure that your persistence
objects are making caching calls from appropriate locations. And, your O/R mapping
tool should provide the ability to generate code that makes caching calls to one
or more leading products.
Ideally, your O/R mapping tool should let you specify which objects you want to
cache and which ones you do not want to cache. The most popular situation is where
transactional objects (single row objects) are cached. However, you can also cache
entire collections and even related objects
Top  Feature 9: Customization of generated code
You’ll always have situations where you need to customize generated code. However,
if you change the generated code, it will most likely get overwritten the next time
you generate code again. And, since software development is an iterative process,
you’ll have to generate code many times.
Additionally, whatever custom code you write must be called when the generated code
is run. And, it must also be able to control the subsequent execution of the generated
code. For example, if your custom code is called before doing an “Insert” and you
find something wrong, you should be able to prevent the “Insert” from actually happening.
To prevent your code from being overwritten, the O/R mapping tool must allow you
to mark your code as “Safe Code” which then does not get overwritten in future code
regenerations. And, to ensure that your custom code gets called seamlessly, the
O/R mapping tool needs to either support the concept of “Hooks” which are calls
made from strategic places in the generated code and the result code returned by
these “Hooks” determines what happens next. Or, the O/R mapping tool needs to let
you derive the generated code and then use polymorphism to actually run your code
instead of the generated code. You can then determine whether to call the “base
class code” or not.
Top  Feature 10: Template customization
A good O/R mapping tool is very likely using code templates to determine how to
generate the code. The O/R mapping tool combines the templates it has with a combination
of your object mapping input and the database schema information to determine exactly
how to generate the code.
Since the O/R mapping tool is generating code from templates, it would be great
if it let you modify these templates (or add new templates) so you could affect
how the generated code should look.
A very simple example would be when you would like to put your own copyright header
in each source code file. If you could go an insert this header in the code template
file, it would automatically get used next time you generate code. You should also
be able to write your own code templates (although this is only for advanced users)
and let the O/R mapping tool use your templates but do everything else the same
way as it always does.
Top  Conclusion
You should seriously consider using an O/R mapping tool as it will save you a
lot of development and testing time. And, when it comes to evaluating which tool
is best for you, you should know what to look for. I hope this article helps you
gain a better understanding of O/R mapping. Top 
About
Iqbal Khan
| Iqbal Khan is the Director Sales & Marketing at AlachiSoft (http://www.alachisoft.com), a leading provider of O/R Mapping tool called TierDeveloper. You can reach him at iqbal@alachisoft.com. |
Click here if you want to know more about
Iqbal Khan.
Other articles that may interest you
|
Average Rating :  |
|
Discussion Forums
Got a programming related question? Hopefully someone has the answer... Want to help out other developers? Visit our discussion forums.
|
|
|
 |
|
|
|
|
Sponsored by:
|
|
|
|
|
|
|
|
New Articles
Exceptions and Performance
Almost every time exceptions are mentioned in mailing lists and newsgroups, people say they're really expensive.Let's examine that claim, shall we?
Creating multilingual websites - Part 1
Extend the existing globalization capabilities of .NET to create flexible and powerful multilingual web sites. First, create a custom ResourceManager, and then create custom localized-capable server controls to easily deploy multilingual functionality.
Parameter passing in C#
Many people have become fairly confused about how parameters are passed in C#, particularly with regard to reference types. This page should help to clear up some of that confusion
|
|
|
|
Most Popular Articles
LDAP, IIS and WinNT Directory Services
This article explains how to use .NET Directory Services to retrieve and search directory objects, create new directory objects and edit or delete existing directory objects. Describes Active Directory Application Mode (ADAM) and how to use the IIS, WinNT and LDAP directory (ADSI) provider.
An in-depth look at WMI and instrumentation, Part II
WMI stands for Windows Management Instrumentation and, as the name indicates, is about managing your IT infrastructure this article is the second part of a two-part series.
An in-depth look at WMI and instrumentation, Part I
WMI stands for Windows Management Instrumentation and, as the name indicates, is about managing your IT infrastructure this article provides an in-depth look at WMI and MOM 2005
|
|
|
|
New Books
Murach's ASP.NET 2.0 Upgrader's Guide: VB Edition
What’s new and how to use it! That’s what this book delivers if you’re a VB developer who’s interested in upgrading from ASP.NET 1.x to ASP.NET 2.0.
C# in easy steps
Learn to program with Microsoft’s premier programming language. No previous programming knowledge is assumed. With numerous easy-to-follow examples, this title explains the essentials of object-oriented programming with C#.
Murach's ASP.NET web programming with VB.NET
Murach's ASP.NET web programming with VB.NET by Doug Lowe and Anne Prince is a in depth training and reference book for ASP.NET programming using VB.NET. The book builds upon Murach's previous books and covers more advanced concepts for programming ASP.NET pages.
|
|
|
|
Got Code?
if you have any article , source code , or anything else you'd like to share with this community that you think others might find useful, please submit it here and we will gladly make it available on this site.
submit@developerland.com.
|
|
|
|
|
|
|
|
|
|