This tutorial is part of a set. Find out more about data access with ASP.NET in the Working with Data in ASP.NET 2.0 section of the ASP.NET site at http://www.asp.net/learn/dataaccess/default.aspx. Working with Data in ASP.NET 2.0 :: Creating a Data Access Layer Introduction As web developers, our lives revolve around working with data. We create databases to store the data, code to retrieve and modify it, and web pages to collect and summarize it. This is the first tutorial in a lengthy series that will explore techniques for implementing these common patterns in ASP.NET 2.0. We'll start with creating a software architecture composed of a Data Access Layer (DAL) using Typed DataSets, a Business Logic Layer (BLL) that enforces custom business rules, and a presentation layer composed of ASP.NET pages that share a common page layout. Once this backend groundwork has been laid, we'll move into reporting, showing how to display, summarize, collect, and validate data from a web application. These tutorials are geared to be concise and provide stepbystep instructions with plenty of screen shots to walk you through the process visually. Each tutorial is available in C# and Visual Basic versions and includes a download of the complete code used. (This first tutorial is quite lengthy, but the rest are presented in much more digestible chunks.) For these tutorials we'll be using a Microsoft SQL Server 2005 Express Edition ...
This tutorial is part of a set. Find out more about data access with ASP.NET in the Working with Data in ASP.NET 2.0 section of the ASP.NET site at http://www.asp.net/learn/dataaccess/default.aspx.Working with Data in ASP.NET 2.0 :: Creating a Data Access Layer IntroductionAs web developers, our lives revolve around working with data. We create databases to store the data, code to retrieve and modify it, and web pages to collect and summarize it. This is the first tutorial in a lengthy series that will explore techniques for implementing these common patterns in ASP.NET 2.0. We'll start with creating a software architecturecomposed of a Data Access Layer (DAL) using Typed DataSets, a Business Logic Layer (BLL) that enforces custom business rules, and a presentation layer composed of ASP.NET pages that share a common page layout. Once this backend groundwork has been laid, we'll move into reporting, showing how to display, summarize, collect, and validate data from a web application. These tutorials are geared to be concise and provide stepbystep instructions with plenty of screen shots to walk you through the process visually. Each tutorial is available in C# and Visual Basic versions and includes a download of the complete code used. (This first tutorial is quite lengthy, but the rest are presented in much more digestible chunks.) For these tutorials we'll be using a Microsoft SQL Server 2005 Express Editionversion of the Northwind database placed in the App_Datadirectory. In addition to the database file, the App_Datafolder also contains the SQL scripts for creating the database, in case you want to use a different database version. These scripts can be also be downloaded directly from Microsoft, if you'd prefer. If you use a different SQL Server version of the Northwind database, you will need to update the NORTHWNDConnectionStringsetting in the application's Web.configfile. The web application was built using Visual Studio 2005 Professional Edition as a file system based Web site project. However, all of the tutorials will work equally well with the free version of Visual Studio 2005,Visual Web Developer. In this tutorial we'll start from the very beginning and create the Data Access Layer (DAL), followed by creating the Business Logic Layer (BLL) in the second tutorial, and working onpage layout and navigation in the third. The tutorials after the third one will build upon the foundation laid in the first three. We've got a lot to cover in this first tutorial, so fire up Visual Studio and let's get started!Step 1: Creating a Web Project and Connecting to the DatabaseBefore we can create our Data Access Layer (DAL), we first need to create a web site and setup our database. Start by creating a new file systembased ASP.NET web site. To accomplish this, go to the File menu and choose New Web Site, displaying the New Web Site dialog box. Choose the ASP.NET Web Site template, set the Location dropdown list to File System, choose a folder to place the web site, and set the language to Visual Basic. 1fo33
Figure 1: Create a New File SystemBased Web SiteThis will create a new web site with a Default.aspxASP.NET page, an App_Datafolder, and a Web.configfile. With the web site created, the next step is to add a reference to the database in Visual Studio's Server Explorer. By adding a database to the Server Explorer you can add tables, stored procedures, views, and so on all from within Visual Studio. You can also view table data or create your own queries either by hand or graphically via the Query Builder. Furthermore, when we build the Typed DataSets for the DAL we'll need to point Visual Studio to the database from which the Typed DataSets should be constructed. While we can provide this connection information at that point in time, Visual Studio automatically populates a dropdown list of the databases already registered in the Server Explorer. The steps for adding the Northwind database to the Server Explorer depend on whether you want to use the SQL Server 2005 Express Edition database in the App_Datafolder or if you have a Microsoft SQL Server 2000 or 2005 database server setup that you want to use instead.Using a Database in the App_DataFolderIf you do not have a SQL Server 2000 or 2005 database server to connect to, or you simply want to avoid having to add the database to a database server, you can use the SQL Server 2005 Express Edition version of the Northwind database that is located in the downloaded website's App_Datafolder (NORTHWND.MDF). A database placed in the App_Datafolder is automatically added to the Server Explorer. Assuming you have SQL Server 2005 Express Edition installed on your machine you should see a node named NORTHWND.MDF in the Server Explorer, which you can expand and explore its tables, views, stored procedure, and so on (see Figure 2). The App_Datafolder can also hold Microsoft Access .mdbfiles, which, like their SQL Server counterparts, are automatically added to the Server Explorer. If you don't want to use any of the SQL Server options, you can always download a Microsoft Access version of the Northwind database file and drop into the App_Datadirectory. Keep in mind, however, that Access databases aren't as featurerich as SQL Server, and aren't designed to be used in web site scenarios. Furthermore, a couple of the 35+ tutorials will utilize certain databaselevel features that aren't supported by Access. 2of33
Connecting to the Database in a Microsoft SQL Server 2000 or 2005 Database ServerAlternatively, you may connect to a Northwind database installed on a database server. If the database server does not already have the Northwind database installed, you first must add it to database server by running the installation script included in this tutorial's download or by downloading the SQL Server 2000 version of Northwind and installation script directly from Microsoft's web site. Once you have the database installed, go to the Server Explorer in Visual Studio, rightclick on the Data Connections node, and choose Add Connection. If you don't see the Server Explorer go to the View / Server Explorer, or hit Ctrl+Alt+S. This will bring up the Add Connection dialog box, where you can specify the server to connect to, the authentication information, and the database name. Once you have successfully configured the database connection information and clicked the OK button, the database will be added as a node underneath the Data Connections node. You can expand the database node to explore its tables, views, stored procedures, and so on.Figure 2: Add a Connection to Your Database Server's Northwind Database Step 2: Creating the Data Access LayerWhen working with data one option is to embed the dataspecific logic directly into the presentation layer (in a web application, the ASP.NET pages make up the presentation layer). This may take the form of writing ADO.NET code in the ASP.NET page's code portion or using the SqlDataSource control from the markup portion. In either case, this approach tightly couples the data access logic with the presentation layer. The recommended approach, however, is to separate the data access logic from the presentation layer. This separate layer is referred to as the Data Access Layer, DAL for short, and is typically implemented as a separate Class 3of33
Library project. The benefits of this layered architecture are well documented (see the "Further Readings" section at the end of this tutorial for information on these advantages) and is the approach we will take in this series. All code that is specific to the underlying data source –such as creating a connection to the database, issuing SELECT, INSERT, UPDATE, and DELETEcommands, and so on – should be located in the DAL. The presentation layer should not contain any references to such data access code, but should instead make calls into the DAL for any and all data requests. Data Access Layers typically contain methods for accessing the underlying database data. The Northwind database, for example, has Productsand Categoriestables that record the products for sale and the categories to which they belong. In our DAL we will have methods like: lGetCategories(),which will return information about all of the categories lGetProducts(), which will return information about all of the products lGetProductsByCategoryID(categoryID), which will return all products that belong to a specified category lGetProductByProductID(productID), which will return information about a particular product These methods, when invoked, will connect to the database, issue the appropriate query, and return the results. How we return these results is important. These methods could simply return a DataSet or DataReader populated by the database query, but ideally these results should be returned using stronglytyped objects. A stronglytyped object is one whose schema is rigidly defined at compile time, whereas the opposite, a loosely typed object, is one whose schema is not known until runtime. For example, the DataReader and the DataSet (by default) are looselytyped objects since their schema is defined by the columns returned by the database query used to populate them. To access a particular column from a looselytyped DataTable we need to use syntax like: DataTable.Rows(index)("columnName"). The DataTable's loose typing in this example is exhibited by the fact that we need to access the column name using a string or ordinal index. A stronglytyped DataTable, on the other hand, will have each of its columns implemented as properties, resulting in code that looks like: DataTable.Rows(index).columnName. To return stronglytyped objects, developers can either create their own custom business objects or use Typed DataSets. A business object is implemented by the developer as a class whose properties typically reflect the columns of the underlying database table the business object represents. A Typed DataSet is a class generated for you by Visual Studio based on a database schema and whose members are stronglytyped according to this schema. The Typed DataSet itself consists of classes that extend the ADO.NET DataSet, DataTable, and DataRow classes. In addition to stronglytyped DataTables, Typed DataSets now also include TableAdapters, which are classes with methods for populating the DataSet's DataTables and propagating modifications within the DataTables back to the database.Note: For more information on the advantages and disadvantages of using Typed DataSets versus custom business objects, refer to Designing Data Tier Components and Passing Data Through Tiers. We'll use stronglytyped DataSets for these tutorials' architecture. Figure 3 illustrates the workflow between the different layers of an application that uses Typed DataSets. 4of33
Figure 3: All Data Access Code is Relegated to the DAL CreatignaTyepdDataSteandTableAdatpreTo begin creating our DAL, we start by adding a Typed DataSet to our project. To accomplish this, rightclick on the project node in the Solution Explorer and choose Add a New Item. Select the DataSet option from the list of templates and name it Northwind.xsd.Figure 4: Choose to Add a New DataSet to Your ProjectAfter clicking Add, when prompted to add the DataSet to the App_Codefolder, choose Yes. The Designer for the Typed DataSet will then be displayed, and the TableAdapter Configuration Wizard will start, allowing you to add your first TableAdapter to the Typed DataSet. A Typed DataSet serves as a stronglytyped collection of data; it is composed of stronglytyped DataTable instances, each of which is in turn composed of stronglytyped DataRow instances. We will create a strongly typed DataTable for each of the underlying database tables that we need to work with in this tutorials series. Let's start with creating a DataTable for the Productstable. Keep in mind that stronglytyped DataTables do not include any information on how to access data from their underlying database table. In order to retrieve the data to populate the DataTable, we use a TableAdapter class, which functions as our Data Access Layer. For our ProductsDataTable, the TableAdapter will contain the methods – GetProducts(), GetProductByCategoryID(categoryID), and so on – that we'll invoke from the 5of33
presentation layer. The DataTable's role is to serve as the stronglytyped objects used to pass data between the layers. The TableAdapter Configuration Wizard begins by prompting you to select which database to work with. The dropdown list shows those databases in the Server Explorer. If you did not add the Northwind database to the Server Explorer, you can click the New Connection button at this time to do so.Figure 5: Choose the Northwind Database from the DropDown ListAfter selecting the database and clicking Next, you'll be asked if you want to save the connection string in the Web.configfile. By saving the connection string you'll avoid having it hard coded in the TableAdapter classes, which simplifies things if the connection string information changes in the future. If you opt to save the connection string in the configuration file it's placed in the <connectionStrings>section, which can be optionally encrypted for improved security or modified later through the new ASP.NET 2.0 Property Page within the IIS GUI Admin Tool, which is more ideal for administrators. 6of33
Figure 6: Save the Connection String to Web.configNext, we need to define the schema for the first stronglytyped DataTable and provide the first method for our TableAdapter to use when populating the stronglytyped DataSet. These two steps are accomplished simultaneously by creating a query that returns the columns from the table that we want reflected in our DataTable. At the end of the wizard we'll give a method name to this query. Once that's been accomplished, this method can be invoked from our presentation layer. The method will execute the defined query and populate a stronglytyped DataTable. To get started defining the SQL query we must first indicate how we want the TableAdapter to issue the query. We can use an adhoc SQL statement, create a new stored procedure, or use an existing stored procedure. For these tutorials we'll use adhoc SQL statements. Refer to Brian Noyes's article, Build a Data Access Layer with the Visual Studio 2005 DataSet Designerfor an example of using stored procedures. 7fo33
Figure 7: Query the Data Using an AdHoc SQL StatementAt this point we can type in the SQL query by hand. When creating the first method in the TableAdapter you typically want to have the query return those columns that need to be expressed in the corresponding DataTable. We can accomplish this by creating a query that returns all columns and all rows from the Productstable:Figure 8: Enter the SQL Query Into the TextboxAlternatively, use the Query Builder and graphically construct the query, as shown in Figure 9. 8of33
Figure 9: Create the Query Graphically, through the Query EditorAfter creating the query, but before moving onto the next screen, click the Advanced Options button. In Web Site Projects, "Generate Insert, Update, and Delete statements" is the only advanced option selected by default; if you run this wizard from a Class Library or a Windows Project the "Use optimistic concurrency" option will also be selected. Leave the "Use optimistic concurrency" option unchecked for now. We'll examine optimistic concurrency in future tutorials.Figure 10: Select Only the "Generate Insert, Update, and Delete statements" OptionAfter verifying the advanced options, click Next to proceed to the final screen. Here we are asked to select which methods to add to the TableAdapter. There are two patterns for populating data: lFill a DataTable –with this approach a method is created that takes in a DataTable as a parameter and 9of33
populates it based on the results of the query. The ADO.NET DataAdapter class, for example, implements this pattern with its Fill()method. lReturn a DataTable – with this approach the method creates and fills the DataTable for you and returns it as the methods return value. You can have the TableAdapter implement one or both of these patterns. You can also rename the methods provided here. Let's leave both checkboxes checked, even though we'll only be using the latter pattern throughout these tutorials. Also, let's rename the rather generic GetDatamethod to GetProducts. If checked, the final checkbox, "GenerateDBDirectMethods," creates Insert(), Update(), and Delete()methods for the TableAdapter. If you leave this option unchecked, all updates will need to be done through the TableAdapter's sole Update()method, which takes in the Typed DataSet, a DataTable, a single DataRow, or an array of DataRows. (If you've unchecked the "Generate Insert, Update, and Delete statements" option from the advanced properties in Figure 9 this checkbox's setting will have no effect.) Let's leave this checkbox selected.Figure 11: Change the Method Name from GetDatato GetProductsComplete the wizard by clicking Finish. After the wizard closes we are returned to the DataSet Designer which shows the DataTable we just created. You can see the list of columns in the ProductsDataTable (ProductID, ProductName, and so on), as well as the methods of the ProductsTableAdapter(Fill()and GetProducts .))(10of33
Figure 12: The ProductsDataTable and ProductsTableAdapterhave been Added to the Typed DataSetAt this point we have a Typed DataSet with a single DataTable (Northwind.Products) and a stronglytyped DataAdapter class (NorthwindTableAdapters.ProductsTableAdapter) with a GetProducts()method. These objects can be used to access a list of all products from code like: Dim productsAdapter As New NorthwindTableAdapters.ProductsTableAdapter() Dim products as Northwind.ProductsDataTable products = productsAdapter.GetProducts() For Each productRow As Northwind.ProductsRow In products Response.Write("Product: " & productRow.ProductName & "<br />") xetNThis code did not require us to write one bit of data accessspecific code. We did not have to instantiate any ADO.NET classes, we didn't have to refer to any connection strings, SQL queries, or stored procedures. Instead, the TableAdapter provides the lowlevel data access code for us. Each object used in this example is also stronglytyped, allowing Visual Studio to provide IntelliSense and compiletime type checking. And best of all the DataTables returned by the TableAdapter can be bound to ASP.NET data Web controls, such as the GridView, DetailsView, DropDownList, CheckBoxList, and several others. The following example illustrates binding the DataTable returned by the GetProducts()method to a GridView in just a scant three lines of code within the Page_Loadevent handler.AllProducts.aspx <%@ Page Language="VB" AutoEventWireup="true" CodeFile="AllProducts.aspx.cs" Inherits="AllProducts" %> <!DOCTYPE html PUBLIC "//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>View All Products in a GridView</title> <link href="Styles.css" rel="stylesheet" type="text/css" />11fo33