// Parameterized query. @ProductName is the parameter
string Command = "Select * from tblProductInventory where ProductName like @ProductName";
SqlCommand cmd = new SqlCommand(Command, con);
// Provide the value for the parameter
cmd.Parameters.AddWithValue("@ProductName", TextBox1.Text + "%");
con.Open();
GridView1.DataSource = cmd.ExecuteReader();
GridView1.DataBind();
在输入框中输入ip'; Delete from tblProductInventory --
,使用SQL Server Profiler
查看,会发现执行如下:
exec sp_executesql N'Select * from tblProductInventory where ProductName like @ProductName',N'@ProductName nvarchar(40)',@ProductName=N'ip''; Delete from tblProductInventory --%'
创建如下的存储过程:
Create Procedure spGetProductsByName
@ProductName nvarchar(50)
as
Begin
Select * from tblProductInventory
where ProductName like @ProductName + '%'
End
测试存储过程Execute spGetProductsByName 'ip'
使用存储过程
//指定存储过程的名字
SqlCommand cmd = new SqlCommand("spGetProductsByName", con);
//指定 T-SQL 命令是存储过程
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@ProductName", TextBox1.Text + "%");
con.Open();
GridView1.DataSource = cmd.ExecuteReader();
GridView1.DataBind();
新建如下的表tblEmployees
,插入一些事例数据:
Create Table tblEmployees
(
EmployeeId int identity primary key,
Name nvarchar(50),
Gender nvarchar(10),
Salary int
)
Insert into tblEmployees values('Mike','Male',5000)
Insert into tblEmployees values('Pam','Female',3500)
Insert into tblEmployees values('John','Male',2350)
Insert into tblEmployees values('Sara','Female',5700)
Insert into tblEmployees values('Steve','Male',4890)
Insert into tblEmployees values('Sana','Female',4500)
注意插入数据的时候,没有指定EmployeeId
创建一个存储过程spAddEmployee
,向表中添加一行数据
Create Procedure spAddEmployee
@Name nvarchar(50),
@Gender nvarchar(20),
@Salary int,
@EmployeeId int Out
as
Begin
Insert into tblEmployees values(@Name, @Gender, @Salary)
Select @EmployeeId = SCOPE_IDENTITY()
End
1.@Name
, @Gender
和@Salary
是输入参数
2.@EmployeeId
是输出参数
3.这个存储过程有2行代码,第一行是向tblEmployees
表中添加数据,第二行是获取自动产生EmployeeId
列的identity
值
测试一下:
Declare @EmpId int
Execute spAddEmployee 'John', 'Male', '7500', @EmpId Out
Print 'Employee Id = ' + Cast(@EmpId as nvarchar(2))
创建如下的页面:
<table style="border: 1px solid black; font-family: Arial">
<tr>
<td>
Employee Name
td>
<td>
<asp:TextBox ID="txtEmployeeName" runat="server">asp:TextBox>
td>
tr>
<tr>
<td>
Gender
td>
<td>
<asp:DropDownList ID="ddlGender" runat="server">
<asp:ListItem>Maleasp:ListItem>
<asp:ListItem>Femaleasp:ListItem>
asp:DropDownList>
td>
tr>
<tr>
<td>
Salary
td>
<td>
<asp:TextBox ID="txtSalary" runat="server">asp:TextBox>
td>
tr>
<tr>
<td colspan="2">
<asp:Button ID="btnSubmit" runat="server" Text="Submit" OnClick="btnSubmit_Click" />
td>
tr>
<tr>
<td colspan="2">
<asp:Label ID="lblMessage" runat="server">asp:Label>
td>
tr>
table>
button的事件如下,向表中添加一条记录,并获取到添加的Id
protected void btnSubmit_Click(object sender, EventArgs e)
{
string CS = ConfigurationManager.ConnectionStrings["DatabaseConnectionString"].ConnectionString;
using (SqlConnection con = new SqlConnection(CS))
{
SqlCommand cmd = new SqlCommand("spAddEmployee", con);
//存储过程类型
cmd.CommandType = CommandType.StoredProcedure;
//添加value
cmd.Parameters.AddWithValue("@Name", txtEmployeeName.Text);
cmd.Parameters.AddWithValue("@Gender", ddlGender.SelectedValue);
cmd.Parameters.AddWithValue("@Salary", txtSalary.Text);
//输出参数
SqlParameter outPutParameter = new SqlParameter();
outPutParameter.ParameterName = "@EmployeeId";
outPutParameter.SqlDbType = System.Data.SqlDbType.Int;
outPutParameter.Direction = System.Data.ParameterDirection.Output;
cmd.Parameters.Add(outPutParameter);
con.Open();
cmd.ExecuteNonQuery();
//获取输出参数的值
string EmployeeId = outPutParameter.Value.ToString();
lblMessage.Text = "Employee Id = " + EmployeeId;
}
}
DataReader
允许你以只进、只读流的方式每次读取一条select
命令返回的记录。这种方式有时候被称为流水游标。使用DataReader
是获取数据最简单的方式,不过它缺乏非连接的DataSet
所具有的排序功能。
DataReader
提供了最快捷且毫无拖沓的数据访问
不能使用new操作符创建一个SqlDataReader
对象,会报错The type 'System.Data.SqlClient.SqlDataReader' has no constructors defined.
SqlDataReader rd = new SqlDataReader();
SqlCommand
对象的ExecuteReader()
方法返回一个SqlDataReader
对象
SqlCommand command = new SqlCommand("Select * from tblProductInventory", connection);
SqlDataReader reader = command.ExecuteReader()
ExecuteReader()
方法可以有一个可以枚举类型CommandBehavior
作为参数的重载版本。一个有用的值是CommandBehavior.CloseConnection
.把它传给ExecuteReader()
方法后,关闭DataReader的同时,DataReader会关闭关联的连接
SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
//不需要关闭Connection,关闭reader就行
reader.Close();
需要注意的一点是SqlDataReader
是connection oriented
,所以要显式的调用 Open()
方法
最简单的使用方式是把SqlDataReader
与 GridView
绑定起来,把它指派给GridView
的DataSource
属性。注意:与SqlConnection
对象一样,要把SqlDataReader
对象包裹在一个using
块中。
string ConnectionString = ConfigurationManager.ConnectionStrings["DBConnectionString"].ConnectionString;
using (SqlConnection connection = new SqlConnection(ConnectionString))
{
connection.Open();
SqlCommand command = new SqlCommand("Select * from tblProductInventory", connection);
using (SqlDataReader reader = command.ExecuteReader())
{
ProductsGridView.DataSource = reader;
ProductsGridView.DataBind();
}
}
通过SqlDataReader
对象的Read()
方法,来循环遍历每一行。
如下的例子,计算10%的折扣:
protected void Page_Load(object sender, EventArgs e)
{
string CS = ConfigurationManager.ConnectionStrings["DatabaseConnectionString"].ConnectionString;
using (SqlConnection con = new SqlConnection(CS))
{
con.Open();
SqlCommand command = new SqlCommand("select * from tblProductInventory02", con);
using (SqlDataReader reader = command.ExecuteReader())
{
//创建DataTable
DataTable sourceTable = new DataTable();
sourceTable.Columns.Add("ID");
sourceTable.Columns.Add("Name");
sourceTable.Columns.Add("Price");
sourceTable.Columns.Add("DiscountedPrice");
while (reader.Read())
{
//计算10%的折扣
int OriginalPrice = Convert.ToInt32(reader["UnitPrice"]);
double DiscountedPrice = OriginalPrice * 0.9;
DataRow datarow = sourceTable.NewRow();
datarow["ID"] = reader["ProductId"];
datarow["Name"] = reader["ProductName"];
datarow["Price"] = OriginalPrice;
datarow["DiscountedPrice"] = DiscountedPrice;
//添加DataRow 到 DataTable
sourceTable.Rows.Add(datarow);
}
GridView1.DataSource = sourceTable;
GridView1.DataBind();
}
}
}
效果如下:
NextResult()
Read()
方法是遍历result set
中的row
,NextResult()
是遍历多个result sets
string ConnectionString = ConfigurationManager.ConnectionStrings["DBConnectionString"].ConnectionString;
using (SqlConnection connection = new SqlConnection(ConnectionString))
{
connection.Open();
SqlCommand command = new SqlCommand("select * from tblProductInventory; select * from tblProductCategories", connection);
using (SqlDataReader reader = command.ExecuteReader())
{
ProductsGridView.DataSource = reader;
ProductsGridView.DataBind();
while (reader.NextResult())
{
CategoriesGridView.DataSource = reader;
CategoriesGridView.DataBind();
}
}
}
当DataReader
遇到数据库里的空值时,它返回一个常量DBNull.Value
。试图访问该值或者装换它的数据会产生异常。因此,在可能出现空值时,必须使用如下的代码对齐进行检测:
int? numberOfHires;
if (reader["NumberOfHires"] == DBNull.Value)
{
numberOfHires = null;
}
else
{
numberOfHires = (int?)reader["NumberOfHires"];
}