asp.net2.0数据访问(1)-入门-创建数据访问层

整个指南系列将从最简单的内容开始,我们会首先创建一个数据访问层(DAL),在DAL中通过强类型数据集(Typed DataSet)访问数据库中的信息。 

一、入门(introduction)

作为Web开发者,我们会一直不断的与数据打交道,比如:创建数据库存储数据;编写代码访问和修改数据;通过Web页面收集和汇总数据等等。

这 个相对来说比较长的指南系列将会揭示asp.net2.0数据操作的通用模式。我们将从创建整个系列的软件架构开始。整个架构将包括DAL(通过强类型数 据集实现),BLL(展示业务逻辑规则)和UI(由asp.net页面组成,而这些页面又都共享使用一个模板来布局)。等这些基础工作完成以后,将开始展 示数据,包括如何显示、汇总、收集和验证数据。

为了让您了解的更加清楚,整个系列将会遵循简单明了和通过大量截图分布演示的风格来展现。每一篇文章都是用C#和VB.NET两种语言编写代码,你可以下载到相应语言的源代码。(作者注:第一篇文章非常长,后面的就按内容分块,相对更好理解一些)

在 整个系列中,我们将会使用SQL SERVER 2005 Express Edition中的示例数据库Northwind,它会被放在项目的App_Date文件夹中,除了数据库文件外,文件夹还包括创建数据库用的SQL脚 本,为您使用不同的数据库版本提供了方便(如果你愿意的话),这些SQL脚本可以在微软的官方网站下载。需要说明的是,如果您选择使用了一个不同的数据库 版本,需要修改Web.config文件中的NORTHWNDConnectionString的内容。整个Web应用程序通过VS2005专业版创建, 项目类型是一个基于文件系统的Web站点项目。当然,系列中的所有内容,都可以非常好地运行在其它免费地VS2005版本或者Visual Web Developer中。

在“入门”章节中,首先创建DAL,接着第二篇文章创建BLL,第三篇开始页面布局和导航。前三篇文章将建立整个系列地基础平台。第一篇文章内容会稍微多一些,现在让我们打开VS开始上路吧!

第1步:创建Web项目并连接数据库

在 我们建立DAL之前,首先创建一个站点,并且安装数据库,下面创建一个新的基于文件系统的ASP.NET站点。操作如下:打开VS的“文件”/“新建网 站”菜单,显示创建新网站对话框,选择“asp.net web site”模板,在位置(location)下来列表中,选择“文件系统”,选择一个文件夹存放Web站点,同时将语言改成C#.


图1   创建新网站

上述步骤将创建一个新的Web站点,包括一个Default.aspx页面,一个App_Data文件夹和一个Web.config文件。

下 一步是通过VS SERVER EXPLORER添加对数据库的引用,通过往SERVER EXPLORE中添加数据库,您可以添加表、存储过程、视图等等。您可以查看表中的数据,也可以手动或通过QUERY BUILDER来创建查询,另外,我们可以指定用于创建强类型数据集的数据库。在我们提供数据库连接字符串信息的同时,VS会自动装载一个下拉列表用来展 示已经在SERVER EXPLORE注册的数据库。

添加northwind数据库的具体步骤取决于,你是想通过App_Data文件夹中的SQL SERVER 2005 EXPRESS EDITION,还是想用SQL SERVER 2000或SQL SERVER 2005的数据库。

1.1使用App_Data中的数据库

如 果您没有SQL SERVER 2000或2005的数据库服务器,或者说您不想往数据库服务器中添加数据库,您可以用SQL SERVER 2005 EXPRESS EDITION版的northwind数据库,您可以通过下载本项目的源代码,然后在App_Data中找到它(NorthWND.MDF).

位 于App_Data文件夹下的数据库会自动添加到SERVER EXPLORE中,加入您的机器已经安装了SQL SERVER 2005 EXPRESS EDITION,您会在SERVER EXPLORE中看到一个northwnd.mdf的节点。您可以展开并查看其中的表、视图、存储过程等。

在App_Data文件夹中,您 同样可以放置MICROSOFT ACCESS的.mdb文件,它同样也会被自动添加到SERVER EXPLORE中,如果您不想使用任何的SQL SERVER版本,可以下载一个MICROSOFT ACCESS版本的数据库,并把它放在App_Data中。但是注意:ACCESS数据库相对于SQL SERVER没有丰富的特性,而且其不是专为Web站点的开发设计的,另外,后续的至少35篇文章中使用的特性可能ACCESS会不支持。


1.2  创建到SQL SERVER 2000或2005的数据库连接

作为另一种方案,您也可以连接已经安装在数据库服务器中的northwind数据库,前提是数据库已经安装到服务器了。如果没有,您可以通过下载本示例教程中的安装脚本或者从微软的网站下载SQL SERVER 2000版的northwind和安装脚本。

如 果您已经安装了northwind,打开VS中的SERVER EXPLORE,右击“Data Connections”节点,选择“添加连接”。如果您没有打开SERVER EXPLORE,可以通过“视图/服务器管理器”或按“ALT+CTRL+S”快捷键打开。打开“添加连接”对话框后,指定要连接的目标服务器,授权信息 和数据库,如果您已经成功配置了数据库连接信息,单击“确定”按钮,数据库就会作为“Data Connections”节点下一个新节点添加到SERVER EXPLORE,您同样可以展开,并查看其中的表、视图、存储过程等。

图2    添加连接

第2步:创建DAL

处 理数据的一个选择是将处理的详细逻辑直接放在显示层(在Web应用程序中,ASP.NET页面组成了显示层),这种形式,通过将ADO.NET写到 ASP.NET页面下的编码区域或者使用SQLDATASOURCE控件。这种途径将DAL和显示层紧密的耦合在一起。推荐的一种途径是将DAL从显示层 分离出来。这个分离出来的层被叫做数据访问层,往往使用一个单独的类库项目来实现。这种架构的优点有很多,而且有许多说明文档。

所有数据底层数据源的代码(如创建连接,进行SELECT,INSERT,UPDATE,DELETE操作)都被放到DAL中,在显示层不能包括任何数据访问的代码,可以通过调用DAL来访问和请求数据。

DAL封装了访问底层数据的典型方法,例如:northwind数据库中有Products和Categories两张表,分别记录了销售的商品和这些商品的类型。在我们的DAL中,可能要创建如下方法:
GetCategories();返回所有类型的信息。
GetProducts();返回所有商品的信息。
GetProductByCategoryID(CategoryID);返回特定类型的商品。
GetProductByProductID(productid);返回某个商品的信息。
这 些方法执行时,会连接数据库,实施查询,返回结果。如何返回这些结果是至关重要的。上述方法可以简单的返回一个dataset或datareader,但 更完美的一种方式是:返回结果作为强类型对象返回。所谓强类型对象就是在编译时就对其架构进行了严格的定义,弱类型恰恰想法,只能在运行时,才被定义。

例 如DataReader和默认的DataSet都是弱类型,只能靠数据查询返回的列来定义其架构。访问一个弱类型的DataTable某一列的方法如下: DataTable.Rows(index)["columnName"].展示了必须通过一个字符串或下标去访问表中的一列。一个强类型的 DataTable可以将表中的每一列实现为属性,当然,访问方式也发生了变化:DataTable.Rows(index).columnName.

为了返回一个强类型的对象,开发者一是可以创建自定义的业务对象或者可以使用强类型的数据集。对于自定义业务对象,开发者往往通过定义一个类来实现,其中类的属性与底层数据库相应表中的列是一一对应的。

一 个强类型的DataSet是VS根据数据库的架构自动产生的。其里面的成员都是强类型的。强类型数据集中包含的类有效地扩展了ADO.NET中的 DataSet,DataTable,DataRow。除了强类型的DataTable,强类型DataSet中还包括TableAdapter,这些类 中包含了操作DataSet中的表和将表中的改变提交到后台数据库的一系列的方法。

我们在整个系列中将使用强类型数据集。下图展示了使用强类型数据集的应用程序层与层之间通信的工作流。


图3    工作流

2.1 创建强类型数据集和TableAdapter

下面开始创建DAL,首先添加一个强类型的数据集到项目中。步骤:右击项目节点,选择“添加新项”,选择DataSet模板,改名为northwind.xsd。

图4   添加强类型数据集

然后,单击“添加”,当提示是否将DataSet添加到App_Code文件夹时,选择“是”。这是,将出现强类型数据集设计器,同时TableAdapter配置向导将会启动,允许您添加第一个TableAdapter到DataSet。

强类型数据集是一个强类型数据的集合,由多个强类型DataTable的实例构成,每个强类型的DataTable由多个强类型的DataRow实例构成。我们将会为在项目中用到的底层数据库中的每个表创建一个相应的强类型DataTable。

下面是为Products表创建一个DataSet中的强类型表。

请 牢记,强类型DataTables不包括访问底层数据库表的任何信息,为了获取数据填充这个表,我们用一个TableAdapter类来充当DAL,对 Products表而言,TableAdapter类将包含以下方法(GetProducts(),GetProductsByCategoryId (categoryid)等)。我们可以在显示层调用这些方法,DataTable在层与层的数据传递过程中充当强类型的对象。

TableAdapter配置向导首先让您选择要操作的数据库,在下拉列表中展示了SERVER EXPLORE中的所有的数据库,如果没有数据库,您可以单击“新建连接”,添加。


选择完数据库后,单击下一步,您要选择是否保存连接到Web.config文件,如果保存连接字符串,那么就不用在TableAdapter类中硬编码了。这样也就避免了一旦将来连接字符串发生改变带来的不必要的麻烦。

如果选择保存到配置文件中,会保存在相应的<connectionstring>节,您同时可以对连接字符串进行加密,以提供其安全性。也可以通过IIS的图形化管理工具中的asp.net2.0的属性页面来修改。(这在某种程度,对管理员是一件好事)。


下 一步,我们开始定义第一个强类型DataTable的架构,而且定义第一个方法以供TableAdapter来操作强类型DataSet。这两个操作,可 以通过创建一个查询,让其返回DataTable相应的列来实现,而且是同步实现的。在向导的最后,我们要给查询命名一个方法名。当所有的这些都完成后, 就可以通过显示层来调用方法了。这个方法将会执行定义的查询形成一个DataTable。

在定义查询之前,首先要知道TableAdapter怎样执行查询,我们可以使用单纯的SQL语句,也可以创建一个新的存储过程,或者使用一个现有的存储过程。在我们的这个系列中,将使用单纯的SQL语句。


那么我们就可以手工输入SQL语句了,通过创建第一个方法,让查询返回相应表中的列,下图展示了创建一个查询返回Products表中所有的行和列。


当然,也可以使用查询生成器,可视化创建查询。


创 建完查询后,在转到下一页面前,单击“高级”按钮,在WEB SITE项目中,“Generate Insert,update,and delete statement”是唯一的默认选中项;如果您的项目是类库或者是Windows项目,“use optimistic concurrency”选项也是被选中的,现在请不要选择这个复选框,对于这一话题,将在以后的文章中探讨。


配置完高级选项后,单击“下一步”到最后一个页面,我们将选择哪个方法添加到TableAdapter中,有两种方式:
填充一个表:创建一个方法,以查询结果生成的DataTable作为参数,并对其进行处理。例如:ADO.NET TableAdapter类调用Fill()方法。
返回一个表:方法用来创建、填充表,表作为方法的返回值。
您可以让TableAdapter实现其中一个或两个方法都实现,您也可以给方法改名。这里我们两个选项全选,但后续的文章中将使用后一种方法。同时将通用的GetData方法名改为GetProducts()。

如果选中了最后一个checkbox,“GenerateDbDirectMethod”将会为TableAdapter创建Insert,Update和Delete方法。

如果不选,所有的更新将通过TableAdapter唯一的方法Update来实施。而唯一的这个方法,对强类型的Dataset,DataTable,DataRow或者行组都是通用的。


单击“完成”完成向导,这时我们在设计器中得到一张表。可以看到表中的所有的列,(ProductId,ProductName等),同时还有ProductTableAdapter的所有方法(Fill方法和GetProducts方法)。


至此为止,我们创建了一个强类型数据集和一个表,和一个强类型的DataAdapter类。这些对象可以用来访问商品列表,代码如下:
NorthwindTableAdapters.ProductsTableAdapter productsAdapter =
    new NorthwindTableAdapters.ProductsTableAdapter();
Northwind.ProductsDataTable products;

products = productsAdapter.GetProducts();

foreach (Northwind.ProductsRow productRow in products)
    Response.Write("Product: " + productRow.ProductName + "<br />");

我们不需要写任何代码,也不需要实例化任何ADO.NET类,不需要去管连接字符串,SQL查询和存储过程。TableAdapter会为我们自动生成这些底层的代码。

本例中的每一个对象都是强类型的,允许VS提供智能感知和编译时的类型判断。大多数的TableAdapter返回的表都可以绑定到Web数据控件(GridView等)。下面的代码演示了如何将GetProducts方法返回的结果绑定到一个GridView。

AllProducts.aspx:
<%@ Page Language="C#" 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/xhtml1-transitional.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" />
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <h2>
            All Products</h2>
        <p>
            <asp:GridView ID="GridView1" runat="server"
             CssClass="DataWebControlStyle">
               <HeaderStyle CssClass="HeaderStyle" />
               <AlternatingRowStyle CssClass="AlternatingRowStyle" />
            </asp:GridView>
             </p>

    </div>
    </form>
</body>
</html>

AllProduct.aspx.cs:
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using NorthwindTableAdapters;

public partial class AllProducts : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        ProductsTableAdapter productsAdapter = new
         ProductsTableAdapter();
        GridView1.DataSource = productsAdapter.GetProducts();
        GridView1.DataBind();
    }
}

这个例子演示了在Page_Load事件下写代码,在以后的文章中,将演示如何使用ObjectDataSource从DAL中获取数据,通过ObjectDataSource,可以不用写任何代码,同时还能得到比较好的分页和排序支持。

第3步:添加带参数的方法到DAL

到 此为止,类ProductTableAdapter只有一个方法(GetProducts方法)用来返回所有商品信息。但有时候,我们可能只想知道某一个 特殊商品的信息,或者某一类型商品的信息,为了在DAL实现类似的功能我们可以往TableAdapter中添加带参数的方法。

下面我们添加GetProductsByCategoryId(categoryId)。步骤:选中设计器中的ProductTableAdapter区域,右击,选择“添加查询”。


当提示用单纯SQL语句或存储过程时,选择SQL语句,接下来选择应用何种SQL查询,由于我们想返回某一类型的商品,所以选择Select语句。


再下一步是定义访问数据库的SQL查询语句,由于想返回某一个类型的商品信息,所以用与GetProducts方法相同的Select语句,然后在后面加上Where子句:Where Categoryid=@Categoryid.@categoryid告诉TableAdapter,要创建的方法需要一个相应类型的输入参数。


最后选择访问数据的方式和新创建的方法的方法名,分别用Fill方式命名FillByCategoryId;为Return a DataTable方式命名为GetProductsByCategoryId。


完成向导,发现设计器中包含了新的方法。


用同样的方法添加GetProductsByProductId(productId)方法。

这些参数化查询可以直接再DataSet设计器测试,右击方法,选择“预览数据”,然后输入参数值,单击“预览”


使用DAL中的GetProductsByCategoryId(categoryId)方法,借助于一个asp.net页面,来展示特定类型的商品,下面的代码展示了类型为“Beverages”的所有商品。

Beverages.aspx:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Beverages.aspx.cs"
    Inherits="Beverages" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
    <link href="Styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <h2>Beverages</h2>
        <p>
            <asp:GridView ID="GridView1" runat="server"
             CssClass="DataWebControlStyle">
               <HeaderStyle CssClass="HeaderStyle" />
               <AlternatingRowStyle CssClass="AlternatingRowStyle" />
            </asp:GridView>
             </p>
    </div>
    </form>
</body>
</html>

Beverages.aspx.cs:
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using NorthwindTableAdapters;

public partial class Beverages : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        ProductsTableAdapter productsAdapter = new
         ProductsTableAdapter();
        GridView1.DataSource =
          productsAdapter.GetProductsByCategoryID(1);
        GridView1.DataBind();
    }
}


第4步:插入、更新、删除数据
通常,有两种方式可以用来插入、更新和删除数据。第一种可以成为“数据库直接方式”。它涉及到创建多个执行插入、更新、删除单一数据记录的命令的方法。

这些方法通过传递一系列的值去完成相应的操作。例如,用这种方式,如果删除Products表中一条记录,需要Delete方法中有一个productId参数,而且参数的类型为整数。


另 外一种方式可以叫做“批量更新方式”(batch update pattern)。通过调用一个方法,来更新整个数据集,数据表或行集。用这种方式,开发者对表中的记录行做了一些操作后,把所有的数据行和表传到 Update方法中,该方法枚举传入的所有行,判断它们是否发生了改变,以此为据完成相应的数据库操作(Delete,Update,Insert)。


TableAdapter 默认使用批量更新方式。但也支持数据库直接方式。以前创建TableAdapter时选中“高级”里面的“Generate Insert,Update and Delete Statement”选项。ProductTableAdapter类中Update方法就实现了批量更新。

如果您刚创建TableAdapter时,选中了“GenerateDBDirectMethod”那么就通过Insert,Update,Delete方法实现了数据库直接方式。

两 种方式,都要使用TableAdapter的InsertCommand,UpdateCommand,DeleteCommand属性去执行 Insert,Update,Delete命令。您可以检查,修改这些属性。通过打开设计器中的TableAdapter的属性窗口。


在检查或修改任何属性时,当单击“CommandText”属性时,将会打开“查询生成器”。


下面的代码演示了如何使用批量更新模式来改变不打折商品和库存不少于25的商品的价格(价格翻倍)。
NorthwindTableAdapters.ProductsTableAdapter productsAdapter =
  new NorthwindTableAdapters.ProductsTableAdapter();

// For each product, double its price if it is not discontinued and
// there are 25 items in stock or less
Northwind.ProductsDataTable products = productsAdapter.GetProducts();
foreach (Northwind.ProductsRow product in products)
   if (!product.Discontinued && product.UnitsInStock <= 25)
      product.UnitPrice *= 2;

// Update the products
productsAdapter.Update(products);

下面的代码演示了如何使用数据库直接模式删除一个商品,更新和新增一个商品。
NorthwindTableAdapters.ProductsTableAdapter productsAdapter =
    new NorthwindTableAdapters.ProductsTableAdapter();

// Delete the product with ProductID 3
productsAdapter.Delete(3);

// Update Chai (ProductID of 1), setting the UnitsOnOrder to 15
productsAdapter.Update("Chai", 1, 1, "10 boxes x 20 bags",
  18.0m, 39, 15, 10, false, 1);

// Add a new product
productsAdapter.Insert("New Product", 1, 1,
  "12 tins per carton", 14.95m, 15, 0, 10, false);

4.1创建自定义的插入、删除和更新方法
用“数 据库直接方式”产生的Insert,Update,Delete方法使用起来有点不灵活,特别是表中有许多字段时,象刚才的代码,如果没有智能提示,那么 Insert和Update方法的参数就会是一个很繁重的工作量,特别是只更新这些列中的某一列时,有很多信息就重复输入了。

可以创建自定义的方法解决上述问题,右击TableAdapter,选择“添加查询”,打开TableAdapter向导,在查询创建页面,创建一个方法,用来添加一个新商品,并且返回新添加商品的ProductId,因此应该选择Insert。


在下一个页面,呈现出插入命令的代码,然后通过在最后添加Select  Scope_IDENTITY()扩展这个命令。这个方法将返回最后一个添加到表中IDENTITY列的值。

注意:要保证Insert语句和Select语句用“;”隔开。


最后命名该方法为InsertProduct()


当再次回到设计器时,您会发现ProductTableAdapter节中新加了一个方法:InsertProduct。如果新表中没有提供对应表中列的一系列参数,很可能时您在Insert语句和Select语句之间忘加“;”了。

默认情况下,插入时不需要查询的,只返回被影响的行数。然而,如果我们想得到插入的值,而不是影响的行数的话,可以修改InsertProduct方法的ExcuteMode属性为:Scalar。


下面的代码演示了InsertProduct方法的使用。
NorthwindTableAdapters.ProductsTableAdapter productsAdapter =
    new NorthwindTableAdapters.ProductsTableAdapter();

// Add a new product
int new_productID = Convert.ToInt32(productsAdapter.InsertProduct
    ("New Product", 1, 1, "12 tins per carton", 14.95m, 10, 0, 10, false));

// On second thought, delete the product
productsAdapter.Delete(new_productID);

第5步:完成DAL
注 意到ProductTableAdapter类通过Products表返回了CategoryId和SupplierId。但没有 CategroyName(在Categories表中)和SupplierName(在supplier表中)。但从道理上讲,展示商品信息时是应该显 示这些信息的。接下来,我们就来扩展最开始创建的方法,GerProducts(),也就是改变DataTable的结构使其包含这些列。

这 样可能会引发一个问题,就是TableAdapter中的Insert,Update,Delete方法都是基于这个方法的(会不会受影响)。庆幸的是, 这些方法不会受到Select子查询的影响。我们可以小心翼翼地将从Categories和Supplier的查询作为子查询,而不是使用joins。使 用上述方法,我们就可以避免重写方法,右击“GetProducts()”,选择“配置”,调整Select语句如下所示:
SELECT     ProductID, ProductName, SupplierID, CategoryID,
QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued,
(SELECT CategoryName FROM Categories
WHERE Categories.CategoryID = Products.CategoryID) as CategoryName,
(SELECT CompanyName FROM Suppliers
WHERE Suppliers.SupplierID = Products.SupplierID) as SupplierName
FROM         Products

当更新完GetProducts()之后,再做查询就包含CategoryName和SupplierName了。


用同样的方法,更新GetProductByCategroyId方法的Select语句。

如 果您用joins语法更新了GetProducts()方法,在“数据库直接模式”下,设计器不会自动产生Inserting,Updating, Deleting方法,您必须象创建InsertProduct方法那样,手动创建这些方法。另外,如果您想用“批量更新模式”,您必须手动更新 InsertCommand,UpdateCommand,DeleteCommand属性的值。

5.1添加现有的TableAdapter
直到现在,我们一直在讨论一个TableAdapter访问一个数据表,然而,Northwind数据库包含了在Web应用程序中使用的很多相关联的表,一个强类型的DataSet可以包括很多相关联的表,因此,为了完成DAL,我们必须添加在另外一些章节使用的一些表。

您可以通过打开设计器,右击,选择“添加/TableAdapter”,就可以添加一个新表和一个新的TableAdapter了。

花一些时间完成下面的TableAdapter和方法,注意:如果您一直跟着整个文章下来,您已经完成了GerProducts()和GetProductByCategoryId(categoryId)方法了。
ProductsTableAdapter
GetProducts:
SELECT ProductID, ProductName, SupplierID,
CategoryID, QuantityPerUnit, UnitPrice, UnitsInStock,
UnitsOnOrder, ReorderLevel, Discontinued ,
(SELECT CategoryName FROM Categories WHERE
Categories.CategoryID = Products.CategoryID) as
CategoryName, (SELECT CompanyName FROM Suppliers
WHERE Suppliers.SupplierID = Products.SupplierID)
as SupplierName
FROM Products
GetProductsByCategoryID:
SELECT ProductID, ProductName, SupplierID, CategoryID,
QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
ReorderLevel, Discontinued , (SELECT CategoryName
FROM Categories WHERE Categories.CategoryID =
Products.CategoryID) as CategoryName,
(SELECT CompanyName FROM Suppliers WHERE
Suppliers.SupplierID = Products.SupplierID)
as SupplierName
FROM Products
WHERE CategoryID = @CategoryID
GetProductsBySupplierID:
SELECT ProductID, ProductName, SupplierID, CategoryID,
QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
ReorderLevel, Discontinued , (SELECT CategoryName
FROM Categories WHERE Categories.CategoryID =
Products.CategoryID) as CategoryName,
(SELECT CompanyName FROM Suppliers WHERE
Suppliers.SupplierID = Products.SupplierID) as SupplierName
FROM Products
WHERE SupplierID = @SupplierID
GetProductByProductID:
SELECT ProductID, ProductName, SupplierID, CategoryID,
QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
ReorderLevel, Discontinued , (SELECT CategoryName
FROM Categories WHERE Categories.CategoryID =
Products.CategoryID) as CategoryName,
(SELECT CompanyName FROM Suppliers WHERE Suppliers.SupplierID = Products.SupplierID)
as SupplierName
FROM Products
WHERE ProductID = @ProductID
CategoriesTableAdapter
GetCategories:
SELECT CategoryID, CategoryName, Description
FROM Categories
GetCategoryByCategoryID:
SELECT CategoryID, CategoryName, Description
FROM Categories
WHERE CategoryID = @CategoryID
SuppliersTableAdapter
GetSuppliers:
SELECT SupplierID, CompanyName, Address,
City, Country, Phone
FROM Suppliers
GetSuppliersByCountry:
SELECT SupplierID, CompanyName, Address,
City, Country, Phone
FROM Suppliers
WHERE Country = @Country
GetSupplierBySupplierID:
SELECT SupplierID, CompanyName, Address,
City, Country, Phone
FROM Suppliers
WHERE SupplierID = @SupplierID

EmployeesTableAdapter
GetEmployees:
SELECT EmployeeID, LastName, FirstName, Title,
HireDate, ReportsTo, Country
FROM Employees
GetEmployeesByManager:
SELECT EmployeeID, LastName, FirstName, Title,
HireDate, ReportsTo, Country
FROM Employees
WHERE ReportsTo = @ManagerID
GetEmployeeByEmployeeID:
SELECT EmployeeID, LastName, FirstName, Title,
HireDate, ReportsTo, Country
FROM Employees
WHERE EmployeeID = @EmployeeID

5.2向DAL中添加自定义代码
加入强类型的DataSet中的TableAdapter和DataTables表示为XML Schema的形式,您可以通过右击“设计器”,选择“查看代码”,来查看XML文件。


这些架构信息在编译或执行时,被转换为C#代码,您可以通过单步调试来查看。可以通过“类视图”来查看自动生成的代码,如果类视图没有打开,可以通过“视图/类视图”菜单或按“CTLR+SHIFT+C"快捷键打开。

通过类视图,可以查看强类型DataSet和TableAdapter类的属性,方法和事件。可以通过双击某个方法查看某个特定方法的实现代码,或者在方法上右击,选择“定义”。


虽 然自动产生代码可以节省大量的时间,但往往很单调,需要适当的修改才能完成一些特定的功能需求。扩展自动产生的代码的风险是:有时工具会重新产生代码,因 而覆盖您自定义的代码。但通过.net2.0 partial类的概念,可以很容易将一个类写成多个文件,就使得我们可以很方便添加属性,方法和事件,而不用担心被覆盖或重写。

为了展示 如何自定义DAL,我们添加一个GetProducts()方法到SupplierRow类。该类表示Supplier表中的一行。每个提供商可能提供零 个或多个商品,所以GetProducts()用来放回某个提供商的商品,首先在App_Code文件夹中创建一个新类,然后添加如下代码:
using System;
using System.Data;
using NorthwindTableAdapters;

public partial class Northwind
{
    public partial class SuppliersRow
    {
        public Northwind.ProductsDataTable GetProducts()
        {
            ProductsTableAdapter productsAdapter =
             new ProductsTableAdapter();
            return
              productsAdapter.GetProductsBySupplierID(this.SupplierID);
        }
    }
}

partial关键字告诉编译器:在生成SupplierRow类时,将包含GetProducts方法,等生成后,同样可以在“类视图”中找到它。


GetProducts()方法可以枚举某个提供商提供的商品,代码如下:
NorthwindTableAdapters.SuppliersTableAdapter suppliersAdapter =
    new NorthwindTableAdapters.SuppliersTableAdapter();

// Get all of the suppliers
Northwind.SuppliersDataTable suppliers =
  suppliersAdapter.GetSuppliers();

// Enumerate the suppliers
foreach (Northwind.SuppliersRow supplier in suppliers)
{
    Response.Write("Supplier: " + supplier.CompanyName);
    Response.Write("<ul>");

    // List the products for this supplier
    Northwind.ProductsDataTable products = supplier.GetProducts();
    foreach (Northwind.ProductsRow product in products)
        Response.Write("<li>" + product.ProductName + "</li>");

    Response.Write("</ul><p> </p>");
}
这些数据可以显示在任何Web数据控件中,下面的页面通过创建一个包含两列的GridView来显示数据。
一个绑定列,用于显示提供商。
一个模板列,包含一个BulletedList控件,用于绑定GetProducts()方法的结果。
下面的代码,展示了SupplierRow类中自定义方法的应用:
SuppliersAndProducts.aspx:
<%@ Page Language="C#" CodeFile="SuppliersAndProducts.aspx.cs"
    AutoEventWireup="true" Inherits="SuppliersAndProducts" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
    <link href="Styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <h2>
            Suppliers and Their Products</h2>
        <p>
            <asp:GridView ID="GridView1" runat="server"
             AutoGenerateColumns="False"
             CssClass="DataWebControlStyle">
                <HeaderStyle CssClass="HeaderStyle" />
                <AlternatingRowStyle CssClass="AlternatingRowStyle" />
                <Columns>
                    <asp:BoundField DataField="CompanyName"
                      HeaderText="Supplier" />
                    <asp:TemplateField HeaderText="Products">
                        <ItemTemplate>
                            <asp:BulletedList ID="BulletedList1"
                             runat="server" DataSource="<%#
                                 ((Northwind.SuppliersRow)((System.Data.DataRowView)
                                 Container.DataItem).Row).GetProducts() %>"
                                 DataTextField="ProductName">
                            </asp:BulletedList>
                        </ItemTemplate>
                    </asp:TemplateField>
                </Columns>
            </asp:GridView>
             </p>

    </div>
    </form>
</body>
</html>

SuppliersAndProducts.aspx.cs:
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using NorthwindTableAdapters;

public partial class SuppliersAndProducts : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        SuppliersTableAdapter suppliersAdapter = new
          SuppliersTableAdapter();
        GridView1.DataSource = suppliersAdapter.GetSuppliers();
        GridView1.DataBind();
    }
}


二、总结
在 创建Web应用程序时,创建DAL是第一步,一定要在创建显示层之前创建。通过VS创建一个基于强类型DataSet的DAL,大概10-15分钟就完成 了(如果不写任何代码的话)。接下来的整个系列都要依赖于该DAL。在下一篇中,我们将定义一些业务规则,而且学习如何在一个单独的业务逻辑层中实现它 们。

快乐编程!!!asp.net2.0数据访问(1)-入门-创建数据访问层

 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值