CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

David Hayden [MVP C#]

         .NET Tutorials, Patterns, and Practices

SqlHelper and Enterprise Library 2.0 DAAB Weren't Intended to be Your Data Access Layer

After several discussions recently, I am suspecting a number of people are using the old SqlHelper and the new Enterprise Library Data Access Application Block as their data access layer, but I don't believe this is the original intent of the Patterns and Practices Group.

I think of SqlHelper and DAAB as the pipes in my house. I hide them behind the wall and stick a "sink", "shower", or "toilet" on the end of them depending on my needs.  Using them as a DAL is like running around the house and drinking from the hose bib :)

When I use the DAAB, I wrap it in a DbHelper class that implements IDbHelper.  Except for a few changes, there is usually a 1:1 ratio between the public "interface" on the DAAB and my IDbHelper interface:

 

public class DbHelper : IDbHelper
{
    // Enterprise Library DAAB - Hidden
    private readonly Database _database = null;

    public DbHelper()
    {
        _database = DatabaseFactory.CreateDatabase();
    }

    #region IDbHelper Members

    public IDataReader ExecuteReader(CommandType commandType, string storedProcedureName)
    {
        return _database.ExecuteReader(commandType, storedProcedureName);
    }

    #endregion
}

 

One could argue if one really needs to go through all this work of wrapping up the DAAB in a helper class. I do it for a few reasons:

  • It gains me a bit more flexibility so that I can add additional public methods via the interface not directly supported by DAAB.
  • I can easily replace the DAAB with a different solution without requiring much effort.
  • The IDbHelper Interface gives me a bit more fine grained testability.

 

Now from here at the minimum you would have a class that uses IDbHelper ( there should be some value add to this class and not just an empty shell around IDbHelper ):

 

public class SqlDataSource : IDataSource
{
    private readonly IDbHelper _helper = null;

    public SqlDataSource(IDbHelper helper)
    {
        _helper = helper;
    }

    #region IDataSource Members

    public IDataReader GetReader(string spName)
    {
        return _helper.ExecuteReader(CommandType.StoredProcedure, spName);
    }

    #endregion
}

 

And you could continue this further if again you are looking for some more granularity in functionality and loose coupling ( or you could remove the intermediate step of SqlDataSource and add the IDbHelper to this class ):

 

public class CustomerDataSource : ICustomerDataSource
{
    private readonly IDataSource _dataSource = null;
    
    public CustomerDataSource(IDataSource dataSource)
    {
        _dataSource = dataSource;
    }
    
    public IDataReader GetCustomers()
    {
        // Do some stuff
        IDataReader dr = _dataSource.GetReader("GetCustomers");
        // Do some stuff
        
        return dr;
    }
}

 

This might all get consumed into a business class using, for example, the ActiveRecord Pattern, if you like using classes and have minimal business rules:

 

public class Customer
{
    // ...
    
    public static List<Customer> GetCustomers()
    {
        ICustomerDataSource source = ...
        
        // Return customers...
    }
}

 

A lot of the classes here are subject to one's development style, opinion, and application needs. Some developers would remove some of the classes and some would rather return a disconnected object ( like DataSet or Entity ) to the business layer rather than an open DataReader.  Many developers smirk at the whole idea of the ActiveRecord Pattern as the idea of combining business rules and data access is crazy. Some people prefer creating custom dataproviders using the built-in DataProvider model in the .NET 2.0 Framework. Many would grab the nearest O/R Mapper to avoid the process :)

My point isn't to argue or defend different architectures, but to merely point out that SqlHelper or DAAB is a helper class. It is the pipes IMHO.  It is low on the food chain and needs to be very much disposable and replaceable.  When SqlHelper or Enterprise Library 2.0 DAAB starts to define or limit your data access layer, you are probably using it wrong :)

 



Comments

Naming is important said:

IDbHelper? What a crap name! That's an obvious smell. If you can only give something a really vague name there's something really wrong with your design -- responsibilities have not been allocated among objects correctly.
# March 16, 2006 2:48 PM

David Hayden said:

Like I said above, one could argue it :)

However, you would have to play with the DAAB to appreciate IDbHelper a bit more. For example, the DAAB doesn't support the return of just a DataTable nor new .NET 2.0 Features like Batch Updates.

The use of DbHelper and IDbHelper eliminate a lot of code redundancy in the DataSource Classes as well as expose additional functionality not directly available in the DAAB.

So I can agree with YAGNI to an extent, but I think it is debatable depending on the reasoning.

Thanks for the comment, Nathan.
# March 16, 2006 2:55 PM

David Hayden said:

You don't like IDbHelper? Alright, make it IDatabase. Make it IPipe. Like I said, you don't need to create it at all if you don't want to.

I don't care if you inject SqlHelper or DAAB as an Interface or assimilate it as part of an abstract DataSource class with common public mehods and abstract methods. You will need the pipe functionality, so you can't call it a smell. It's a necessary evil :)

The fact that you can create the data layer in so many ways is not the point. The point is that SqlHelper or DAAB plays a "minor" role and is not dealt with directly by the upper layers of your application.

Tough crowd :) Please use your real name in the future :)
# March 16, 2006 3:34 PM

John Papa said:

I think what David is getting at here is that it is better to abstract the Ent Lib DAAB from your application rather than have Ent Lib code embedded througout your app. The 2 upsides to this aproach that I see immediately are that you can pull Ent Lib's DAAB out and swap it with something else if need be and you can extend its features with your own custom features. Like David said, you don't get batch update support directly through the Ent Lib DAAB, so if you want it you should consider abstracting it. Thus, the Ent Lib DAAB is part of your DAL, but not solely you DAL.

I agree that the Ent Lib is not enough on its own so I generally extend it. Do I have as many classes as shown in this post, no. But David is not saying you need all of these classes and inerfaces. It is just an example as he clearly states.

# March 16, 2006 4:03 PM

David Hayden said:

Thanks, John. Those were the points I was trying to convey, albeit perhaps a bit unsuccessfully :)
# March 16, 2006 5:11 PM

Eric Wise said:

I've actually gone both routes before with abstracting and just using it. I have to go with David that it is entirely situational but I also lean towards nathan in that most times when I was done I looked back and never really needed to pull it out.

I will say in david's defense that the amount of work to create a wrapper isn't substantial at all so *shrug*.

I will add a point though that the Ent. Lib is a community pattern with excellent documentation and the chances of having a new dev come on board and know how to use it are pretty good compared to a new developer coming on board and having to use a wrapper whose naming conventions may not be like anything else out there. This would represent a learning curve spike and productivity lose from a business perspective.
# March 16, 2006 5:29 PM

Jeremy Miller said:

Nice post David. We use a homegrown equivalent to the DAAB or NHibernate for persistence, but either way we always have strongly-typed wrapper services and interfaces around the low level plumbing. It's a definite no-brainer. Business logic classes should never get exposed to low level ADO.Net plumbing.

And chalk me up as one of those people that don't care for the Active Record style of persistence, at least in .Net anyway.
# March 16, 2006 5:30 PM

David Hayden said:

Good points, Eric. I have yet to pull out the helper classes as well, but like you said, wrapping it is child's play.
# March 17, 2006 1:13 AM

David Hayden said:

Jeremy,

I suspected you weren't a big fan of the Active Record Pattern :)

I can't say I am either for more sophisticated projects, but it is a nice middle ground for those primarily database-driven applications that have very little business rules but for which a bit of abstraction from the database may be in order.

It would be interesting to read a similar post from you on the subject, because I think your superior TDD skills would probably illuminate the subject even more. Your MVP posts associated with the UI were excellent. It would be awesome to see your thoughts on the data side.

# March 17, 2006 1:34 AM
Check out Devlicio.us!

This Blog

Syndication

News

CodeBetter.Com Home