65.9K
CodeProject 正在变化。 阅读更多。
Home

ADO.NET 入门教程

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.79/5 (77投票s)

2012年4月6日

CPOL

8分钟阅读

viewsIcon

442505

downloadIcon

10558

使用一个简单应用程序理解 ADO.NET 的入门教程。

引言

本文旨在帮助理解 ADO.NET 中可用的各种数据访问概念和类。本文面向绝对的初学者,讨论了使用 ADO.NET 进行数据访问的各种技术。

背景

ADO.NET 是 Microsoft .NET 框架随附的一组类,用于促进托管语言的数据访问。ADO.NET 已经存在很长时间了,它提供了一套全面完整的数据访问库。ADO.NET 的优势首先在于它允许应用程序使用相同的方法访问各种类型的数据。如果我知道如何使用 ADO.NET 访问 SQL Server 数据库,那么通过使用不同的一组类,就可以使用相同的方法访问任何其他类型的数据(如 Oracle 或 MS Access)。其次,ADO.NET 提供了两种数据访问模型:一种是连接模型,我可以在其中保持与数据库的连接并执行数据访问;另一种方式是将所有数据获取到 ADO.NET 对象中,使我们能够对断开连接的对象执行数据访问。

注意:许多开发人员和开发公司现在正在使用 ORM 来执行数据访问,而不是使用 ADO.NET。ORM 开箱即用地提供了大量数据访问功能,并使开发人员不必一遍又一遍地编写繁琐的数据访问代码。尽管如此,我认为作为一名 .NET 开发人员,了解和理解 ADO.NET 至关重要,因为它能更好地理解数据访问方法。此外,仍有许多开发公司在使用 ADO.NET。

让我们尝试通过以下图表来可视化 ADO.NET 数据访问。

ADO.NET article image

上图显示 ADO.NET 可以与任何类型的应用程序一起使用,即,它可以从 Windows Forms 应用程序、ASP.NET 应用程序或 WPF 和/或 Silverlight 应用程序中使用。此外,下面的数据存储可以是任何数据存储,如 SQL Server、Access 或 Oracle。这仅仅是使用适合该数据存储的一组正确类的问题,而方法论将保持不变。

使用代码

让我们尝试通过编写一个小型 Web 应用程序来理解一些 ADO.NET 类和方法。此应用程序使用 Microsoft 的一个示例数据库(Pubs 数据库的子集),我们将使用此数据库来理解 ADO.NET 的各种类和方法。我们将使用特定于 SQL Server 的 ADO.NET 类,但一旦理解了它们,基本原理将保持不变,并且可以应用于任何数据存储。

在深入研究代码之前,我们需要了解一些重要的 ADO.NET 对象。在典型的需要数据访问的场景中,我们需要执行四项主要任务:

  1. 连接到数据库
  2. 将请求传递给数据库,即,诸如 select、insert 或 update 之类的命令。
  3. 获取结果,即,行数和/或受影响的行数。
  4. 存储结果并将其显示给用户。

这可以可视化为:

ADO.NET article image

现在我们需要了解如何使用 ADO.NET 实现这些功能。

连接

ADO.NET Connection 类用于建立与数据库的连接。Connection 类使用 ConnectionString 来标识数据库服务器位置、身份验证参数以及连接数据库的其他信息。此 ConnectionString 通常存储在 web.config 文件中。

<connectionStrings>
  <add name="MyConnectionString" 
     connectionString ="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\PUBS.MDF; 
                        Integrated Security=True;User Instance=True" />
</connectionStrings>

让我们看看如何使用 SqlConnection 类来建立与数据库的连接。

private SqlConnection con = null;
con = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString);

现在我们的数据库连接已准备就绪。每当我们想检索数据时,只需打开连接,执行操作,然后关闭连接。

存储结果

在我们开始理解如何对数据库执行命令之前,我们首先需要了解如何存储结果,以及如何将这些结果显示给用户。为了掌握如何存储结果,我们需要了解一些 ADO.NET 对象。

  • DataReader - DataReader 是一个可以用来从数据库中顺序访问结果的对象。DataReader 用于获取查询执行过程中的向前只读顺序结果。它与 Command 对象一起使用(稍后将看到其用法)。
  • Dataset - Dataset 可以被认为是数据库的内存表示。DataSet 是一个断开连接的数据访问对象。查询结果可以存储在 Dataset 中。DataSet 包含 DataTableDataTable 包含 DataRowDataColumnDataSetDataTable 可以与 Command 和 DataAdapter 对象一起使用来存储查询结果。
  • DataAdapter - DataAdapter 对象用于使用查询结果填充 DataSet/DataTable。这可以被认为是连接模型和断开连接数据模型之间的适配器。Command 对象将用于执行查询,而 DataAdapter 将使用此 Command 对象并将来自数据库的查询结果填充到 DataSet/DataTable 中。

注意:

  1. 还有更多用于存储结果的对象,但在本文中我们将主要使用这些对象。
  2. 这些对象的使用和实现将在下一节中介绍,因为在此之前需要理解 Command 对象。

命令

一旦连接就绪,下一步就是告诉数据库我们需要在数据库上执行什么操作。这可以使用 Command 对象来完成。我们将使用 SqlCommand 来告诉数据库我们需要执行的操作。数据库的典型命令是:

  1. Select 命令 - 这将向应用程序返回一组行。
  2. Insert 命令 - 这将返回插入的行数。
  3. Delete 命令 - 这将返回删除的行数。
  4. Update 命令 - 这将返回更新的行数。

注意:本文仅讨论数据操作命令。

所有这些命令都期望 SQL 语法。此 SQL 可以从应用程序中传递,也可以以存储过程的形式编写并通过 SqlCommand 执行。

将存储过程与 Command 一起使用

如果我们要将存储过程与 Command 对象一起使用,则需要将其指定为:

cmd = con.CreateCommand();
// This will specify that we are passing the stored procedures name
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = CommandName; // This will be the stored procedures name

如果存储过程需要一些参数,我们可以通过创建 SqlParameter 对象实例来传递这些参数,如下所示:

SqlCommand cmd = con.CreateCommand();
// This will specify that we are passing the stored procedures name
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = CommandName; // This will be the stored procedures name
SqlParameter param = new SqlParameter("@id", txtSearch.Text);
cmd.Parameters.Add(param);

从应用程序通过 Command 传递 SQL 查询

如果我们要从应用程序传递 SQL 查询,我们可以使用 SqlCommand 如下:

SqlCommand cmd = con.CreateCommand();
cmd.CommandType = CommandType.Text;   //This will specify that we are passing query from application
string query = "select * from Authors";
cmd.CommandText = query;

这里有一个重要的事情需要理解,那就是 SqlParameters。很多时候我们需要在 SQL 查询中传递参数。这可以通过两种方式完成:我们可以使用字符串连接创建一个查询,例如:

SqlCommand cmd = con.CreateCommand();
//This will specify that we are passing query from application
cmd.CommandType = CommandType.Text;
string query = "select * from Authors where authorId = '" + txtSearch.Text + "'";
cmd.CommandText = query;

不推荐这样做,因为这种方法容易出错,并且容易受到 SQL 注入攻击。所以,每当我们想向查询传递参数时,首选的方法是使用 SqlParameters。相同的查询可以这样写:

SqlCommand cmd = con.CreateCommand();
//This will specify that we are passing query from application
cmd.CommandType = CommandType.Text;
string query = "select * from Authors where authorId = @id";
cmd.CommandText = query;

SqlParameter param = new SqlParameter("@id", txtSearch.Text);
cmd.Parameters.Add(param);

使用 SqlParameters 可以使代码更清晰、错误更少且更安全(相对而言)免受 SQL 注入的攻击。

执行 Select 命令

现在让我们看看如何以 DataTable 的形式检索 Select 命令的结果。

public DataTable ExecuteSelectCommand(string CommandName, CommandType cmdType)
{
    SqlCommand cmd = null;
    DataTable table = new DataTable();

    cmd = con.CreateCommand();

    cmd.CommandType = cmdType;
    cmd.CommandText = CommandName;

    try
    {
        con.Open();

        SqlDataAdapter da = null;
        using (da = new SqlDataAdapter(cmd))
        {
            da.Fill(table);
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
    finally
    {
        cmd.Dispose();
        cmd = null;
        con.Close();
    }

    return table;
}

public DataTable ExecuteParamerizedSelectCommand(string CommandName, 
                 CommandType cmdType, SqlParameter[] param)
{
    SqlCommand cmd = null;
    DataTable table = new DataTable();

    cmd = con.CreateCommand();

    cmd.CommandType = cmdType;
    cmd.CommandText = CommandName;
    cmd.Parameters.AddRange(param);

    try
    {
        con.Open();

        SqlDataAdapter da = null;
        using (da = new SqlDataAdapter(cmd))
        {
            da.Fill(table);
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
    finally
    {
        cmd.Dispose();
        cmd = null;
        con.Close();
    }

    return table;
}

执行 Update、Delete 和 Insert 命令

insert、update、delete 等命令通过调用 SqlCommandExecuteNonQuery 方法来执行。让我们看看如何编写一个简单的函数来执行这些命令。这些命令可以通过从应用程序传递查询或通过调用存储过程(如我们上面看到的)来使用。

public bool ExecuteNonQuery(string CommandName, CommandType cmdType, SqlParameter[] pars)
{
    SqlCommand cmd = null;
    int res = 0;

    cmd = con.CreateCommand();

    cmd.CommandType = cmdType;
    cmd.CommandText = CommandName;
    cmd.Parameters.AddRange(pars);

    try
    {
        con.Open();

        res = cmd.ExecuteNonQuery();            
    }
    catch (Exception ex)
    {
        throw ex;
    }
    finally
    {
        cmd.Dispose();
        cmd = null;
        con.Close();
    }

    if (res >= 1)
    {
        return true;
    }
    return false;
}

使用示例应用程序

应用程序中首先要注意的是,它包含一个负责所有 ADO.NET 逻辑的类。DataAccess 类(文件:DataAccess.cs)包含所有 ADO.NET 类和方法。所有页面都使用此类。此类可以在任何应用程序中重用,只需进行一些小的应用程序特定更改。该类的类图是:

ADO.NET article image

示例应用程序包含四个页面:

  • Authors.aspx
  • Titles.aspx
  • AddAuthors.aspx
  • AddTitles.aspx

作者页面,即 Authors.aspxAddAuthors.aspx,使用存储过程执行操作,而标题页面将所有查询从应用程序传递到数据库。我们主要实现了 Select 和 Insert 命令,但 Update 和 Delete 可以与 Insert 在同一思路下实现。

关于该应用程序,有几点值得提及:

  • 在任何情况下都不应将此视为数据访问层的设计参考。这仅用于演示 ADO.NET 逻辑。
  • 代码的编写方式是为了提供从初学者的角度清晰的理解,也就是说,经验丰富的程序员会发现代码中有很多可能的优化。
  • 未提供客户端或服务器端验证,因为这不属于本文的范围。
  • 此应用程序没有(在架构和外观方面)设计。

关注点

由于 ADO.NET 已经存在很多年了,许多人会认为这篇文章写得太晚了,可能毫无用处。但写这篇文章的目的是针对那些仍处于软件开发早期阶段的开发人员。此外,ORM 的存在使得 ADO.NET 对于许多开发公司来说已经过时,但了解 ADO.NET 的工作原理可能仍然有助于提高数据访问的理解。

历史

  • 2012 年 4 月 5 日:初版。
© . All rights reserved.