Main Points

This Data Access Layer (DAL) project stands on it's own, especially since it's being designed for reuse throughout the system for many purposes. However, in these tests, I will be trying to retrieve database data for a link factory, click here to read about that background. Well, if you've been following my recent pages, you'll know I'm reading up a storm. Several of the books do have some interesting discussion of data access layers (DAL). Christian Darie's implementation in Professional Search Engine Optimization with ASP.NET is probably especially good for a small to medium site. He actually creates two DALs, one for a project in his chapter on IP Cloaking, and the other in his case study where he builds a complete site. However, I'm looking ahead to when Earth Chronicle is growing into a larger site and trying to do some things now that will architecturally put us in a better more modular, more flexible position. I've done little more than crack the cover of Todd Golding's Professional .NET 2.0 Generics, but the sample chapter I'd read which got me interested in the book in the first place, was sufficient to communicate the flexibility and performance benefits of generics. That will help explain why I'm looking at a different DAL implementation which incorporates generics.

Marco Bellinaso recommends a generics-based solution in ASP.NET 2.0 Website Programming: Problem - Design - Solution. In a demonstration of an ObjectDataSource control, he creates a Customer class to store the database data using a SqlCommand that populates a generic List. It's simple and only uses a constructor and defines some standard properties for the class. It seems to work fairly similarly to how I can build a class to encapsulate the page data. The page data can then be drawn into the LinkFactory to make the necessary links. I'm still considering the database access. Marco writes everything into the Customer class, I already know I want to include a helper function similar to Christian's DAL for his IP Cloaking example. However, I also don't want to overbuild something I'm not yet ready to control. I like to do things "right" and sometimes I need to back off and take smaller bites that I can chew. This will definitely evolve as we go.

Generic List Implementation

I created a couple of dummy properties so I could structure my code similarly to Marco's Customer class to start, and built the constructor to take advantage of them. That now compiles fine, so I can get down to the interesting part. Unfortunately, starting with Marco's code requires building the entire block and then having to test and debug later. I hate that.

I had to fix some compilation errors. I was missing the System.Data.SqlClient namespace so I added that. I'd imported System.Configuration instead of System.Web.Configuration so my web applications couldn't find WebConfigurationManager which represents the Web.config files. Now that I've fixed that, I can access the Web.config file to pull the connection string. I've reassigned the pair of constructor methods. Previously, both were public. However, I need one with three parameters to store the path information for each page used internally for the getPage() method. Therefore, I've set that one to private. I left the constructor with zero parameters public so I can create an instance of my object and run the getPage() method from it. I think that's a little better. I also worked out my issues with calling getPage in the first place. Intellisense in Visual Studio Express would not give it to me. Duh! I wrote it as a static method, so naturally it wouldn't support operating from an instance. I removed the static reference and that took care of that.

I managed to get everything rewritten and it compiles, but the page still throws errors at run time when it's trying to fill the list. I'm not really comfortable using the generic list yet, I also question using it when I'm just returning one item in the list. My code also has multiple constructors which I haven't really done before, and I don't understand Marco Bellinaso's code example well enough to customize it for my needs. I'm going to save it, so I have the option to go back and do some debugging with it later for learning. Maybe once I get into .NET 2.0 Generics it will become obvious, or maybe Marco's book simply can't be referenced piecemeal. Maybe you need to read it straight through.

Anyway, I'm going to try incorporating some more of Christian Darie's ideas. He explains himself and his code much better, so I have a clearer understanding of what's going on. I can also test the code step by step which I wasn't able to do with Marco's. I like building the data access layer in pieces first, before I have to wire it into my link factory. Christian's examples also ring with me more. Marco takes the application code and the data access routines and has them all together. Christian breaks it down into smaller pieces and uses helper functions which Marco uses frequently, but not in this example. On the one hand that may mean that Marco Bellinaso's code is better and more advanced. However it makes me nervous, and it does not run; whatever the case I'm in over my head, and the code I'm writing certainly isn't good code. Let's try a different approach.

Multiple Class Data Access

Well, I've created my first helper method. Christian includes it in his class, appending it to the end of his Data Access class. However, he's also configuring his SqlCommand object for use with the other methods in the class. I'd like this to be a little more generic, and then specify the implementation in a second class; then the work I'm doing now can be extended to other classes as I go. Before we go anywhere though, testing testing, testing. OK! Success! Let's check things out...

// A base helper function to be used to attach any specific connection to any specific SqlCommand

// This is the real method, but it's sequestered for testing
// public static SqlCommand createSqlCommand(string connectionNameInWebDotConfig)
public static string createSqlCommand(string connectionNameInWebDotConfig)
{
.
.
.
}

First, I have a comment; the method name should clearly identify it, but that's no reason not to make add a little explanation, this will appear directly above the method when testing is complete. However, this method, createSqlCommand(), won't work for testing; because it returns an object of SqlCommand type, public static SqlCommand createSqlCommand(...). Therefore, I've created a temporary method declaration which returns a string I can pass to the page, to make sure everything is OK. This is a public function that can be accessed by other classes, and a static function so that you don't have to create an instance of it. It's going to be a helper function, so there shouldn't be any instances of it lying around. The actual command will be added later either from a Stored Procedure or from text, so for right now it only needs one parameter, the name of the connection which is stored in the Web.config file. The abstraction we're creating for use by other functions is an empty command object for a particular database, all they have to do is provide the name of a connection string; once that's done, you only need to add SQL and send.

public static string createSqlCommand(string connectionNameInWebDotConfig)
{
// Take the name of a connection in the Web.config (which is passed in as a parameter) and retrieve the connection string
string connectionString = WebConfigurationManager.ConnectionStrings[connectionNameInWebDotConfig].ConnectionString;

// Use the connection string to prepare a connection to the database
SqlConnection connectionToTheDatabase = new SqlConnection(connectionString);

// Create the SqlCommand to contain the commands for the database and attach the connection to it.
SqlCommand commandForTheDatabase = connectionToTheDatabase.CreateCommand();

// return commandForTheDatabase;

// Testing
string testVariable = commandForTheDatabase.ToString();
return testVariable;
}

Next, I've created the following code inside the createSqlCommand() method; this creates the connection and declares that it's to be used for the set of SQL commands that we'll eventually put into it. I've defined a variable named connectionString that keeps the actual connection string; using the WebConfigurationManager I use the parameter passed in the createSqlCommand call, connectionNameInWebDotConfig to grab the actual connection string from the web.config. With the connection string, we create a connection to the database, connectionToTheDatabase. Then we create the SqlCommand object and define the connection string which it's supposed to use. Although it's commented out for testing, the final step is to return the command object. Note that all of this is done based on a connection name from the web.config which is passed as the original parameter. This is what makes this a helper method for data access. This method doesn't actually do anything, there's no database connection and no command actually being created. Another class is necessary to assign an actual connection name which then creates an instance of a SqlCommand which can be used to connect to a database. This is also the reason that this is a static method. It makes access to this method easier, and we never want to create an instance of a helper anyway - ie we'd never want to hit a database with an empty command object. Some more complete object with SQL and a place to store data is the type of thing we want to create an instance of, and this is simply an assistant method for that operation.

Finally, since this is part of testing, I create a string variable that I can return to make sure everything is OK so far. I take the command object which I eventually want to return as the method output and temporarily output it as a string. Now I just need to call it.

<span class="testOutput"><%= BetaTestingDatabase04BaseDataAccess.createSqlCommand("SqlTestingDb") %></span>

Here's the way I'm calling this from the page. It's the same style of code render block that I use for the link factory. This is a quick and easy way to make sure that the method can be accessed from the page, and that it does what I need it to do. And here's the output. System.Data.SqlClient.SqlCommand Because this simple text appears, we know that by passing a working connection name to the helper function, it's able to generate the SqlCommand object we want to output. To be sure, this only tells us that it exists, but we'll test additional functionality as it becomes testable. I've even wrapped a span with a new class around this to highlight the text output.

Now to be sure I'm cheating. As we continue with testing I keep revising and revising these methods until I get what I want. While I'm going to preserve the code for this webpage so that it will continue working, I'm not going to preserve each individual test as you see above, the only record will be here. The alternative is to have a mess of classes like BetaTestingDatabase04BaseDataAccessTest1, BetaTestingDatabase04BaseDataAccessTest2, BetaTestingDatabase04BaseDataAccessTest3, etc. and that seems like a mess to me right now. I can always change my mind and do future projects that way. So the text you see here on the page is a record of this phase of development. We're only going to wind up with one BetaTestingDatabase04BaseDataAccess class.

Commanding a Database

Now that we have a helper method, it's time to use it. It's time to issue a SQL command to the database, maybe even rip some data out of it.

public static class BetaTestingDatabase04PagePathsDataAccess
{

// This method creates a command for the Testing Database

// Real Method declaration
//public static SqlCommand prepTheConnectionToTheTestingDatabase()
public static string createACommandThatNeedsSqlForTheTestingDatabase()
{
SqlCommand commandForTheTestingDatabaseThatNeedsSql = BetaTestingDatabase04BaseDataAccess.createSqlCommand("SqlTestingDb");

// return commandForTheTestingDatabaseThatNeedsSql;
// Testing
string testVariable = commandForTheTestingDatabaseThatNeedsSql.ToString();
return testVariable;
}

}

As in the helper class, I've temporarily hidden the real method declaration so I can pass a testing string. Also as before, I'm using my testing variable to convert the SqlCommand into a string and return the string as output. In between, I have a simple line that calls the helper function. It passes in the name of the connection from the web.config, and receives an real command object needing only some SQL in a stored procedure or a string of text to go live. Everything else is handled by the helper function. And it only takes the following to pull the results into the webpage.

<span class="testOutput"><%= BetaTestingDatabase04PagePathsDataAccess.createACommandThatNeedsSqlForTheTestingDatabase() %></span>

And it's working beautifully. System.Data.SqlClient.SqlCommand. This let's us pass the connection name to a SqlCommand the way we're really going to do it, passing it from one class to the helper class which returns the prepared SqlCommand. So let's amp this up a bit. I want to pour the SQL into the command in a reusable way; so that I can copy the function, swap out the SQL and run a completely different query against the database. Let's see if we can do that and output the SQL.

SELECT PagePaths.PageID, PagePaths.PageName, WebsitePaths.WebsitePathName, FolderPaths.FolderPathName FROM PagePaths INNER JOIN WebsitePaths ON PagePaths.WebsitePathID = WebsitePaths.WebsitePathID INNER JOIN FolderPaths ON PagePaths.FolderPathID = FolderPaths.FolderPathID

OK, I'm using a separate function to input the SQL, so aside from removing the testing information, there's really no changes to the previous code. I'm thinking that I'll replicate that method into command objects to connect to each of the databases I need access to, and that will be a part of the DAL that lies on top of the helper functions. Then in production I'll have a layer on top of it which inserts all the SQL, just like I'm doing with this function. Creating the SqlCommand and the helper function will be functions that support all database activity, while any particular page or portion of the application will be built on the SQL layer which sits on top of that.

In some cases you'd use Stored Procedures instead of a SQL layer like this; in fact stored procedures are frequently diagrammed out as a separate layer which is what gave me the idea for this architecture. Marco Bellinaso makes a persuasive case for passing SQL as text in certain situations; my case, where I'm looking at potentially having to deal with multiple different database configurations whether Access, MySQL, and / or MS SQL, is the textbook case for using text instead of stored procedures. Stored procedures are highly proprietary and are hardwired into the database itself; therefore moving from one database to another is very difficult. That's bad since I don't know if I'll have the same database a couple years from now, and if that will be the same database I'll be using a few years after that. I'd really prefer not rewrite the DAL completely each time I have to move, so SQL text it is. That way I only have to edit a few words in each command to switch providers from SqlClient to whatever else I might need. Here's the function I'm using to incorporate the SQL as well as testing parameters.

// This method adds a SQL statement in text to the SqlCommand

// Real Method declaration
public static string createACommandLoadedWithSqlForTheTestingDatabase()
{
SqlCommand commandLoadedWithSqlForTheTestingDatabase = BetaTestingDatabase04PagePathsDataAccess.createACommandThatNeedsSqlForTheTestingDatabase();
string sqlText = "SELECT PagePaths.PageID, PagePaths.PageName, WebsitePaths.WebsitePathName, FolderPaths.FolderPathName FROM PagePaths INNER JOIN WebsitePaths ON PagePaths.WebsitePathID = WebsitePaths.WebsitePathID INNER JOIN FolderPaths ON PagePaths.FolderPathID = FolderPaths.FolderPathID";

commandLoadedWithSqlForTheTestingDatabase.CommandText = sqlText;

// return commandLoadedWithSqlForTheTestingDatabase;

// Testing
string testVariable = commandLoadedWithSqlForTheTestingDatabase.CommandText.ToString();
return testVariable;
}

I should note that for this page, I don't want a ton of files lying around (I've got four already), so even though these will be separate in production, the method that creates the SqlCommand object and the method that adds the SQL are both in the BetaTestingDatabase04PagePathsDataAccess class. That said, the guts of this portion is creating a SqlCommand using the createACommandThatNeedsSqlForTheTestingDatabase() method. Then I create a string variable sqlText that I write my SQL statement to. Finally, I set the CommandText property of the command to my new sqlText variable. As always, I cap this with the testing code to convert the command into the text of the SQL statement and return that to this page. I'm guessing you could write it yourself now, but the page grabs this using...

<blockquote class="testOutput">
<%= BetaTestingDatabase04PagePathsDataAccess.createACommandLoadedWithSqlForTheTestingDatabase() %>
</blockquote>

This is shaping up nicely. I now have a simple, straightforward, robust architecture that I understand and can implement for the low level database work. It's quite straightforward to ramp up for production. You'll note that it's still a static method because the whole thing is a helper function; it creates a complete command including the SQL and the connection to a specific database; it just doesn't do anything with it. So the only thing I have left to do is... yup, actually hit the database, pull some data out, and do something with it (at the very least store it somewhere). So let's move on to constructing our database access layer, phase two.