当前位置:站长之家学习教程认证考试Macrmedia认证 → 文章内容

ADO.NET详细研究--DataReader终结篇

减小字体 增大字体 作者:不详  来源:YesAdmin.Com  发布时间:2005-9-15 0:22:59

  这一次我们将把DataReader了结,同时我们提到的有些技巧与DataReader无关但是是很基本的也很有用的技巧。
  一,参数化查询
  在上一篇文章发表以后不少网友提意见说代码不规范,没有对sql使用参数,这确实是很大一个漏洞,所以我在这里首先谈一下参数化查询问题。
  使用参数化查询的好处:可以防止sql注入式攻击,提高程序执行效率。
  针对sql server .net data Provider,我们可以使用@作为前缀标记的参数。比如:
  const string connStr = "Data source=bineon;user=sa;password=test;initial catalog=northwind;";
  string sql = "select ProductID,ProductName from Products";
  sql += " where CategoryID = @CategoryID and ProductID < @CategoryID ";
  SqlConnection conn = new SqlConnection(connStr);
  SqlCommand cmd = new SqlCommand(sql,conn);
  cmd.Parameters.Add("@CategoryID",CategoryIDValue);
  cmd.Parameters.Add("@MaxProductID",MaxProductIDValue);
  conn.Open();
  SqlDataReader reader = cmd.ExecuteReader();
  上面的代码段在定义sql语句的时候使用了两个参数@CategoryID和@CategoryID。为了是参数在执行过程中获得具体值,我们使用Prarmeter对象,通过它把参数添加到Command对象上,这样就获得参数化查询。
  当然上面使用的add方法有其他重载版本,比如我们可以自己定义Parameter对象然后再添加:
  SqlParameter para = new SqlParameter("@CategoryID",CategoryIDValue);
  cmd.Parameters.Add(para);
  上面SqlParameter的构造函数也有多个重载版本。具体可以查看msdn。
   注意:上面的参数必须使用@前缀,另外也不仅仅是查询才能使用参数,其他更新数据库的操作类似的都能采用参数。
   上面我们给出了针对sql server参数化查询的方法,现在我们讨论在OLEDB 和ODBC中指定参数。
   其实这两种Provider都不支持指定参数的方法,但是我们可以在查询中使用(?)作为占位符,去指定参数将出现的位置。
  sql = "select ProductID,ProductName from Products";
  sql += " where CategoryID =? and ProductID < ?";
  接下来我们同样应该把Parameter对象添加到Command的Parameters集合里面,但是这个时候注意参数添加的顺序必须和你使用?的顺序相通,这个是与上面sql server .net data Provider不同的地方。
  OleDbCommand cmd = new OleDbCommand(sql,conn);
  cmd.Parameters.Add(“CatID”,CategoryIDValue);
  cmd.Parameters.Add(“MaxProductID”,MaxProductIDValue);
  如果上面添加参数的次序弄反了,那么MaxProductIDValue将被指定到第一个?那里,那么就出错了。另外上面的参数名CatID和MaxProductID无所谓,你怎么命名都可以,甚至是空串也行。
   注意:上面参数名无所谓,但是添加参数的次序很重要,不能颠倒。同样的其他更新数据库的操作也支持(?)占位符。
  
  二,使用输出参数检索数据
  这种方法的前提是使用存储过程。其实对支持存储过程的DBMS比如sql server来说,其上的所有操作都应该使用存储过程,以获得更好的执行效率。
  比如我现在需要在我的联系人数据库中找出一个和指定ID相同的联系人的姓名(关于联系人数据库请看我的上一篇文章),我应该怎么做呢?一个办法是使用DataReader,但是效率如何?另外也许我们可以选择更好的ExecuteScalar(),但是如果我想知道的是联系人的姓名和电话呢?ExecuteScalar()的效率确实比DataReader好,但是它只能返回单个值,这个时候它也不能满足要求。我们这里使用存储过程输出参数来解决这个问题。存储过程如下:
  CREATE PROCEDURE GetInfo
  (
  @FID int,
  @Fname varchar(8)  output,
  @Fphone varchar(12) output
  )
   AS
  Select @Fname = Fname,@Fphone = Fphone
  from friend
  where Fid = @Fid
  GO
  上面的关键字output指明参数是输出参数。
  然后我们编写代码:
  SqlConnection conn = new SqlConnection(connStr);
  SqlCommand cmd = conn.CreateCommand();
  cmd.CommandText = "GetInfo";
  cmd.CommandType = CommandType.StoredProcedure;
  上面的代码新建conn对象和cmd对象,并把cmd对象的执行命令指定为名为GetInfo的存储过程。接下来我们需要给cmd对象的Parameters集合添加Parameter对象了。
  SqlParameter param = cmd.Parameters.Add("@Fid",16);
  param = cmd.Parameters.Add("@Fname",SqlDbType.VarChar,8);
  param.Direction = ParameterDirection.Output;
  param = cmd.Parameters.Add("@Fphone",SqlDbType.VarChar,8);
  param.Direction = ParameterDirection.Output;
  我们注意到了上面的@Fname和@Fphone参数添加的时候指定了参数为输出方向,这个就是和存储过程里面的参数方向是一致的。下面我们执行命令同时获得对应的值。
  conn.Open();
  cmd.ExecuteNonQuery();
  string Fname = cmd.Parameters["@Fname"].Value.ToString();
  string Fphone = cmd.Parameters["@Fphone"].Value.ToString();
  conn.Close();
   三,检索多个无关的结果集
   有时候我们需要对不同的表(也可能是相同的表,但是查询内容不同)进行无关的查询,比如我想查看所有联系人的姓名,然后在查看所有联系人的住址。当然这个需要我们完全可以一个sql语句搞定,也不需要所谓的多个记录集,但是请允许我以这个需求来演示多个记录集的操作。
   多个查询语句之间使用;分开。具体代码如下:
  SqlConnection conn = new SqlConnection(connStr);
  SqlCommand cmd = conn.CreateCommand();
  string sqla = "select Fname from friend";
  string sqlb = "select Fphone from friend";
  cmd.CommandText = sqla + ";" + sqlb;
  然后我们可以和以往一样获得DataReader,但是由于是多个记录集,我们读取完第一个记录集以后如果使用下一个记录集呢?答案是NextResult()方法,该方法为bool类型,如果有下一个记录集就返回真,否则为假。
  conn.Open();
  SqlDataReader reader= cmd.ExecuteReader();
  int i = 1;
  do
  {
   Console.WriteLine("第" + i.

[1] [2]  下一页