1.2 Approaches to persistence in .NET                        

We’ve discussed how, in any sizeable application, you need a persistence layer to handle loading and saving data. Many approaches are available when you’re building this persistence layer, and each has advantages and disadvantages. Some popular choices are as follow:

■ Hand coding

■ DataSets

■ LINQ-to-SQL

■ NHibernate (or similar)

■ ADO.NET Entity Framework

Despite the fact that we highly recommend NHibernate, it’s always wise to consider the alternatives. As you’ll soon learn, building applications with NHibernate is straightforward, but that doesn’t mean it’s perfect for every project. In the following sections, we examine and compare these strategies in detail, discussing the implications for database access and the user interface.

1.2.1 Choice of persistence layer          

In your applications, you’ll often want to load, manipulate, and save database items. Regardless of which persistence approach you use, at some point ADO.NET objects must be created and SQL commands must be executed. It would be tedious【乏味的】 and unproductive to write all this SQL code each time you have to manipulate data, so you can use a persistence layer to take care of these low-level steps.

The persistence layer is the set of classes and utilities used to make life easier when it comes to saving and loading data. ADO.NET lets you execute SQL commands that perform the persistence, but the complexity of this process requires that you wrap these commands behind components that understand how your entities should be persisted. These components can also hide the specifics of the database, making your application less coupled【耦合】 to the database and easier to maintain. For example, when you use a SQL identifier containing spaces or reserved keywords, you must delimit this identifier. Databases like SQL Server use brackets for that, whereas MySQL uses back-ticks. It’s possible to hide this detail and let the persistence layer select the right delimiter.

Based on the approach you use, the internals of the persistence layer differ widely.

HAND-CODED PERSISTENCE LAYER

Hand-coding a persistence layer can involve a lot of work; it’s common to first build a generic set of functions to handle database connections, execution of SQL commands, and so on. Then, on top of this sublayer, you have to build another set of functions that save, load, and find your business entities. Things get much more involved【复杂】 if you need to introduce caching, business-rule enforcement, or handling of entity relationships.

Hand-coding your persistence layer gives you the greatest degree of flexibility and control; you have ultimate design freedom and can easily exploit specialized database features. But it can be a huge undertaking and is often tedious and repetitive work, even when you use code generation.

DATASET-BASED PERSISTENCE LAYER

Visual Studio lets you effortlessly generate your own persistence layer, which you can then extend with new functionality with few clicks. The classes generated by Visual Studio know how to access the database and can be used to load and save the entities contained in the DataSet.

Again, a small amount of work is required to get started. You have to resort to hand-coding when you need more control, which is usually inevitable (as described in section 1.3).

NHIBERNATE PERSISTENCE LAYER

NHibernate provides all the features required to quickly build an advanced persistence layer in code. It’s capable of loading and saving entire graphs of interconnected objects while maintaining the relationships between them.

In the context of an auction application (such as eBay), NHibernate lets you easily save an Item and its Bids by implementing a method like this:

public void Save(Item item) {

     OpenNHibernateSession();

     session.Save(item);

     CloseNHibernateSession();

}

Here, session is an object provided by NHibernate. Don’t worry about understanding the code yet. For now, we want you to see how simple the persistence layer is with NHibernate. You’ll start using NHibernate in chapter 2, where you’ll discover that it’s straightforward to execute persistence operations. All you need to do is write your entities and explain to NHibernate how to persist them. Before moving on to a deeper discussion of NHibernate, let’s take a quick look at the newest generation of persistence technologies introduced by Microsoft.

LINQ TO SQL–BASED PERSISTENCE LAYER

Language INtegrated Query (LINQ) was introduced in 2007 by Microsoft. It allows for query and set operations, similar to what SQL statements offer for databases directly within .NET languages like C# and Visual Basic through a set of extensions to these languages. LINQ’s ambition is to make queries a natural part of the programming language. LINQ to SQL provides language-integrated data access by using LINQ’s extension mechanism. It builds on ADO.NET to map tables and rows to classes and objects.

LINQ to SQL uses mapping information encoded in .NET custom attributes or contained in an XML document. This information is used to automatically handle the persistence of objects in relational databases. A table can be mapped to a class, the table’s columns can be mapped to properties of the class, and relationships between tables can be represented by properties. LINQ to SQL automatically keeps track of changes to objects and updates the database accordingly through dynamic SQL queries or stored procedures. Consequently, when you use LINQ to SQL, you don’t have to provide the SQL queries yourself most of the time.

LINQ to SQL has some significant limitations when compared to NHibernate. For example, its mapping of classes to tables is strictly one-to-one, and it can’t map base class properties to table columns. Although you can create a custom provider in LINQ, LINQ to SQL is a SQL Server–specific solution.

ADO.NET ENTITY FRAMEWORK

The Microsoft ADO.NET Entity Framework is a new approach to persistence, available since .NET 3.5 SP1. At a high level, it proposes to provide a persistence solution similar to NHibernate, but with the full commercial support and backing of Microsoft. This promises to be an attractive option for developers who require a vendor-supported solution. But at the time of this writing, the Entity Framework is early beta software, and its feature set is incomplete.

The ADO.NET Entity Framework 1.0 version supports multiple databases and more complex mapping. But it won’t support true “object-first” development, where you design and build, and then generate the database tables from that mapping, until version 2—planned for late 2009 at the earliest. For situations requiring a robust ORM, NHibernate still offers significant advantages.