ADO.NET数据访问技术入门

ADO.NET概览

在应用程序开发过程中,大多数时候都需要与数据库进行交互。在.NET问世之前,常用的有ODBCOLEDBADO等数据访问技术。而在.NET下,Microsoft推荐使用ADO.NET这种全新的数据处理方式。

ADO.NET包括两个核心组件:数据提供程序和数据集。数据提供程序用于连接到数据源,支持数据访问和处理。数据集支持数据以关联的方式,在断开连接的情况下独立的缓存数据,根据需要更新数据源。

每个数据源提供程序都有各自的命名空间,并且都把各自所连接的数据源类型作为其前缀。如System.Data.SqlClient 命名空间是 SQL Server 的 .NET Framework 数据提供程序;System.Data.OracleClient 命名空间是用于 Oracle 的 .NET Framework 数据提供程序。

.NET下每个数据提供程序都具备以下两项相同的核心功能:

 通过与数据源的活动链接来访问数据。

 与断开连接的数据集和数据表进行数据交换。

System.Data.SqlClient命名空间概览

.NET下访问SQL Server常用的有System.Data.SqlClientSystem.Data.OleDb这两个命名空间,但前者相对更高效,本实例也是基于System.Data.SqlClient进行讲解。下表所列是SqlClient命名空间的一些比较重要的类。

  

ADO.NET访问SQL Server示例

先在Microsoft SQL Server Management Studio中测试一下该T-SQL语句。后面的示例中将以此T-SQL语句来讲解。

select * from employees where employeeid between 2 and 6  

查询结果如下:

  

那么在利用C#构建应用程序时,如何在代码中完成数据访问功能呢。请看示例代码:

示例代码A

using System;

using System.Data;

using System.Data.SqlClient;

namespace SqlServerProvider

{

    class Program

    {

        static void Main(string[] args)

        {

            // 设置连接字符串

            string connString = @"

            Server =.;

            Integrated Security=True;

            Initial Catalog = Northwind

         ";

            // 设置查询字符串,硬编码方式

            string sqlqry = @"select * from employees where employeeid between 2 and 6";

            // 声明数据连接和数据读取器对象变量

            SqlConnection conn = null;

            SqlDataReader reader = null;

            try

            {

                conn = new SqlConnection(connString);

                SqlCommand cmdqry = conn.CreateCommand();

                cmdqry.CommandType = CommandType.Text;

                cmdqry.CommandText = sqlqry;

                conn.Open();

                reader = cmdqry.ExecuteReader();

                Console.WriteLine(

                   "This program demonstrates the use of "

                 + "the SQL Server Data Provider."

                );

                Console.WriteLine(

                   "Querying database {0} with query \n{1}\n"

                 , conn.Database

                 , cmdqry.CommandText

                );

                Console.WriteLine("First Name\tLast Name\n");

                while (reader.Read())

                {

                    Console.WriteLine(

                       "{0} | {1}"

                     , reader["FirstName"].ToString().PadLeft(10)

                     , reader[1].ToString().PadLeft(10)

                    );

                }

                Console.ReadKey();

            }

            catch (Exception e)

            {

                Console.WriteLine("Error: " + e);

                Console.ReadKey();

            }

            finally

            {

                // 关闭连接

                reader.Close();

                conn.Close();

            }

        }

    }

}

   程序运行结果:

示例很简单,就是先设置好查询语句,在稍微复杂的程序中也可以动态拼接字符串来构建T-SQL语句,接着设置SqlCommand实例对象的CommandType的属性为SQL文本命令,设置其CommandText属性为构建好的T-SQL语句,然后调用执行命令的方法即可。

这种硬编码的方式是完全有效的,动态拼接T-SQL语句的方式特点是简单易学,但存在一个较大弊端。由于数据库中表的字段类型多种多样,在程序中动态的构建一个复杂的T-SQL语句,包括查询、更新、删除等,是一件不容易控制的事,往往拼接出来的T-SQL语句是不符合T-SQL语法要求的。实际上这种方式执行起来相对低效,并且会因此承担SQL注入攻击的风险。

相对较好的方法是使用命令参数。命令参数在命令文本中起到一个占位符的作用,给将要被替代的值做一个标记。在SQL Server中使用命名参数(named parameters,这些参数以@符号做前缀,后面是参数名。下面请看使用命令参数的示例:

示例代码B:

using System;

using System.Data;

using System.Data.SqlClient;

namespace SqlServerProvider

{

    class Program

    {

        static void Main(string[] args)

        {

            int iMinValue = 2;

            int iMaxValue = 6;

            // 设置连接字符串

            string connString = @"

            Server =.;

            Integrated Security=True;

            Initial Catalog = Northwind

         ";

            // 设置查询字符串,命令参数方式

            string sqlqry = @"select * from employees where employeeid between @MinValue and @MaxValue";

            // 声明数据连接和数据读取器对象变量

            SqlConnection conn = null;

            SqlDataReader reader = null;

            try

            {

                conn = new SqlConnection(connString);

                SqlCommand cmdqry = conn.CreateCommand();

                cmdqry.Prepare();

                cmdqry.Parameters.Add("@MinValue"SqlDbType.Int);

                cmdqry.Parameters.Add("@MaxValue"SqlDbType.Int);

                cmdqry.CommandType = CommandType.Text; 

                cmdqry.CommandText = sqlqry;

                cmdqry.Parameters["@MinValue"].Value = iMinValue;

                cmdqry.Parameters["@MaxValue"].Value = iMaxValue;

                conn.Open();

                reader = cmdqry.ExecuteReader();

                Console.WriteLine(

                   "This program demonstrates the use of "

                 + "the SQL Server Data Provider."

                );

                Console.WriteLine(

                   "Querying database {0} with query \n{1}\n"

                 , conn.Database

                 , cmdqry.CommandText

                );

                Console.WriteLine("First Name\tLast Name\n");

                while (reader.Read())

                {

                    Console.WriteLine(

                       "{0} | {1}"

                     , reader["FirstName"].ToString().PadLeft(10)

                     , reader[1].ToString().PadLeft(10)

                    );

                }

                Console.ReadKey();

            }

            catch (Exception e)

            {

                Console.WriteLine("Error: " + e);

                Console.ReadKey();

            }

            finally

            {

                // 关闭连接

                reader.Close();

                conn.Close();

            }

        }

}

}

程序运行结果:

可以发现,示例代码A与示例代码B所获取的数据结果是一致的。与示例代码A不同的是,在示例代码B中,首先创建了iMinValueiMaxValue两个样例数据然后向SqlCommand对象实例的Parameters集合属性添加@MinValue@MaxValue这两个参数,最后在执行命令前设置参数的值。其余的都与示例代码A相同。

SqlCommand对象的Parameters集合是CommandTextSQL字符串的参数值来源,SQL不必用到其中的全部参数,甚至可以完全不用,但不能使用Parameters集合外的任何参数。SQL语句中的参数值不是在给Parameters集合中的成员赋值时就被替换,二是在提交至数据库服务器时才会发生替换。

命令参数具备以下优点:

 变量及其在SQL中的使用位置的映射关系十分清晰,便于代码阅读和理解。

 通过参数可以使用Prepare方法,使得代码运行更快。

上面两种方式是足以应对一般的中小型系统了,但如果从性能上仔细斟酌的话,使用存储过程又显得更胜一筹。存储过程是允许重复执行某个任务的SQL语句,只需要在数据库中创建某个存储过程一次,便可在程序中多次使用。可提高程序的可维护性,允许程序以统一、优化的方式访问数据库。可以创建不带任何参数的存储过程,也可以创建带有输入或输出的参数。默认返回一个整数值0,也可返回一个或多个结果集。

先在Microsoft SQL Server Management Studio中测试一下该T-SQL语句创建存储过程。

CREATE procedure pro_Test

@MinValue int,

@MaxValue int

as

select * from employees where employeeid between @MinValue and @MaxValue

然后利用下面的命令和参数值执行存储过程,结果与本文最开始的查询示例结果相同。

Execute @return = pro_Test

@MinValue=2,

@MaxValue=6

创建好的存储过程可以在程序中被调用,也可以被其它的存储过程所调用。下面请看在程序中调用存储过程的示例。

示例代码C:

using System;

using System.Data;

using System.Data.SqlClient;

namespace SqlServerProvider

{

    class Program

    {

        static void Main(string[] args)

        {

            int iMinValue = 2;

            int iMaxValue = 6;

            // 设置连接字符串

            string connString = @"

            Server =.;

            Integrated Security=True;

            Initial Catalog = Northwind

         ";

            // 声明数据连接和数据读取器对象变量

            SqlConnection conn = null;

            SqlDataReader reader = null;

            try

            {

                conn = new SqlConnection(connString);

                SqlCommand cmdqry = conn.CreateCommand();

                cmdqry.Prepare();

                cmdqry.Parameters.Add("@MinValue"SqlDbType.Int);

                cmdqry.Parameters.Add("@MaxValue"SqlDbType.Int);

                cmdqry.CommandType = CommandType.StoredProcedure;

                cmdqry.CommandText = "pro_Test";

                cmdqry.Parameters["@MinValue"].Value = iMinValue;

                cmdqry.Parameters["@MaxValue"].Value = iMaxValue;

                conn.Open();

                reader = cmdqry.ExecuteReader();

                Console.WriteLine(

                   "This program demonstrates the use of "

                 + "the SQL Server Data Provider."

                );

                Console.WriteLine(

                   "Querying database {0} with query \n{1}\n"

                 , conn.Database

                 , cmdqry.CommandText

                );

                Console.WriteLine("First Name\tLast Name\n");

                while (reader.Read())

                {

                    Console.WriteLine(

                       "{0} | {1}"

                     , reader["FirstName"].ToString().PadLeft(10)

                     , reader[1].ToString().PadLeft(10)

                    );

                }

                Console.ReadKey();

            }

            catch (Exception e)

            {

                Console.WriteLine("Error: " + e);

                Console.ReadKey();

            }

            finally

            {

                // 关闭连接

                reader.Close();

                conn.Close();

            }

        }

    }

}

程序运行结果:

所获取的数据结果与前两个示例是一致的。示例C只是在示例B的基础上做了很少的改动。因为是调用存储过程,所以不需要设置查询字符串,更改一下SqlCommand实例对象的CommandType属性为存储过程,指定其CommandText属性为存储过程的名称,其余与示例B完全相同。不带参数的存储过程比这更显简单,就不再单独介绍了。

欢迎迈进ADO.NET的大门,里面的世界更精彩!

原文地址:https://www.cnblogs.com/hans_gis/p/2032499.html