一,参数化查询
  使用参数化查询的好:可以防止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象添加到CommandParameters集合里面,但是候注意参数添加的序必和你使用?序相通,个是与上面sql server .net data Provider不同的地方。
  OleDbCommand cmd = new OleDbCommand(sql,conn);
  cmd.Parameters.Add(“CatID”,CategoryIDValue);
  cmd.Parameters.Add(“MaxProductID”,MaxProductIDValue);
  如果上面添加参数的次序弄反了,那MaxProductIDValue将被指定到第一个?那里,那就出了。另外上面的参数名CatIDMaxProductID无所,你怎命名都可以,甚至是空串也行。
   注意:上面参数名无所,但是添加参数的次序很重要,不能倒。同的其他更新数据的操作也支持(?)占位符。
  
  二,使用出参数索数据
  这种方法的前提是使用存储过程。其实对支持存储过程的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.ToString() + "记录集内容如下:\n");
   while(reader.Read())
   {
   Console.WriteLine(reader[0].ToString() + "\t");
   }
   i++;
  }while(reader.NextResult());
  注意:由于DataReader本身向前只的特性,您不能比多个记录集的内容,也不能在多个记录集中来回移多个果集,数据取器定位在第一个记录集上,个和数据取器的read()方法不同(方法默记录集之前)。
  另外个例子仅仅时演示多个无关记录集的使用方法,所以不要追究例子的实际。另外当我需要索相记录信息,多表查询也是一个很好的选择,也就是使用Sql join查询
  四,其他相
   索二制数据
  索二制数据的候我CommandBehavior.SequentialAccess举值传递给ExecuteReader方法。另外就是要注意从 记录取信息的候必按照你的sql句的取。比如:
  Sql = “select pub_id,pr_info,logo from pub_info where pub_id=’0763’ “;
  那取的候必先取得pub_id,然后才是pr_info,再接着logo,如果你取了pr_info以后又想pub_info这时你将得到异常。另外需要注意的是取大量二制数据的候比好的法是使用GetBytes方法。下面的代演示如果logo的二制数据。
  System.IO.MemoryStream stream = new System.IO.MemoryStream();
  System.IO.BinaryWriter writer = new System.IO.BinaryWriter(stream); 
  int BufferSize = 1024;
  byte[] Buffer = new Byte[BufferSize];
  long Offset = 0;
  long BytesRead = 0;
  do
  {
  BytesRead = reader.GetBytes(2,Offset,Buffer,0,BufferSize);
  writer.Writer(Buffer,0,(int)BytesRead);
  writer.Flush();
  Offset += BytesRead;
  }
  while(BytesRead == BufferSize);
  索模式信息
  如果我只想取得数据表的模式信息,怎么办DataReaderGetSchemaTable方法可以足我的要求。
  string sql = "select Fid,Fname,Fphone from friend";
  cmd.CommandText = sql;
  conn.Open();
  SqlDataReader reader = cmd.ExecuteReader();
  DataTable SchemaTable = reader.GetSchemaTable();
  然后我可以遍DataTable得所有模式信息
  DataRowCollection SchemaColumns = SchemaTable.Rows;
  DataColumnCollection SchemaProps = SchemaTable.Columns; 
  foreach(DataRow SchemaColumn in SchemaColumns)
  {
    foreach(DataColumn SchemaColumnProp in SchemaProps)
    {
  Console.WriteLine(SchemaColumnProp.ColumnName + "=" + SchemaColumn[SchemaColumnProp.ColumnName].ToString());
    }
  }
  但是上面的效率不高,因不需要取数据集,但是程序实际上做了个工作。一个可行的解决法是把CommandBehavior.SchemaOnly举传递给ExecuteRader方法,另外的法就是构造特殊的sql命令,比如:
  Sql = “select Fid,Fname,Fphone from friend where Fid = 0”
  
  DataReader的功能基本上就介完了,如果需要更详细请查msdn