在开发一个大型的项目的时候,数据库在多表,表关联复杂的情况下,使用存储过程是一种理想的选择,存储过程可以帮助我们处理一些数据
层逻辑比较复杂的事务。存储过程在首次运行时将被编译,因此在多次调用的时候会大大节省数据库服务器的负担,提高程序的运行效率。
但是在.net里调用存储过程的方法是比较痛苦的,特别是在多个传入传出的情况下。
如下面的一个存储过程:
CREATE PROCEDURE MEMBER_TEACHER_GET
@pid as int=null, --教师代号
@depart as int=null, --教师部门
@uname as nvarchar(18)='', --登陆名
@tname as nvarchar(20)='', --真实姓名
@status as char(10)='', --状态
@count as tinyint=null --真分页时所用
AS
--处理过程省略
GO
@pid as int=null, --教师代号
@depart as int=null, --教师部门
@uname as nvarchar(18)='', --登陆名
@tname as nvarchar(20)='', --真实姓名
@status as char(10)='', --状态
@count as tinyint=null --真分页时所用
AS
--处理过程省略
GO
在传统上调用存储过程的方法如下:
string conn_str=this.txtConn.Text.Trim();
SqlConnection myconn=new SqlConnection(conn_str);
SqlCommand mycomm=new SqlCommand("MEMBER_TEACHER_GET",myconn);
mycomm.CommandType=CommandType.StoredProcedure;
SqlParameter myp1=new SqlParameter("@pid",SqlDbType.Int,4);
mycomm.Parameters.Add(myp1);
mycomm.Parameters["@pid"].Value="1001";
SqlParameter myp2=new SqlParameter("@depart",SqlDbType.Int,4);
mycomm.Parameters.Add(myp2);
mycomm.Parameters["@depart"].Value="1000";
SqlParameter myp3=new SqlParameter("@uname",SqlDbType.NVarChar,18);
mycomm.Parameters.Add(myp3);
mycomm.Parameters["@uname"].Value="t1";
SqlParameter myp4=new SqlParameter("@tname",SqlDbType.NVarChar,20);
mycomm.Parameters.Add(myp4);
mycomm.Parameters["@tname"].Value="教师1";
SqlParameter myp5=new SqlParameter("@status",SqlDbType.TinyInt,1);
mycomm.Parameters.Add(myp5);
mycomm.Parameters["@status"].Value="1";
SqlDataAdapter myAdapter=new SqlDataAdapter();
myAdapter.SelectCommand=mycomm;
DataTable d=new DataTable();
myAdapter.Fill(d);
myAdapter.Dispose();
this.dataGrid1.DataSource=d;
SqlConnection myconn=new SqlConnection(conn_str);
SqlCommand mycomm=new SqlCommand("MEMBER_TEACHER_GET",myconn);
mycomm.CommandType=CommandType.StoredProcedure;
SqlParameter myp1=new SqlParameter("@pid",SqlDbType.Int,4);
mycomm.Parameters.Add(myp1);
mycomm.Parameters["@pid"].Value="1001";
SqlParameter myp2=new SqlParameter("@depart",SqlDbType.Int,4);
mycomm.Parameters.Add(myp2);
mycomm.Parameters["@depart"].Value="1000";
SqlParameter myp3=new SqlParameter("@uname",SqlDbType.NVarChar,18);
mycomm.Parameters.Add(myp3);
mycomm.Parameters["@uname"].Value="t1";
SqlParameter myp4=new SqlParameter("@tname",SqlDbType.NVarChar,20);
mycomm.Parameters.Add(myp4);
mycomm.Parameters["@tname"].Value="教师1";
SqlParameter myp5=new SqlParameter("@status",SqlDbType.TinyInt,1);
mycomm.Parameters.Add(myp5);
mycomm.Parameters["@status"].Value="1";
SqlDataAdapter myAdapter=new SqlDataAdapter();
myAdapter.SelectCommand=mycomm;
DataTable d=new DataTable();
myAdapter.Fill(d);
myAdapter.Dispose();
this.dataGrid1.DataSource=d;
其中大部分的时间都放在对参数的传入上了。调用一个存储过程尚是如此,在一个大一点的项目里存储过程几百的个情况下,这样就会给程序
开发带来很大的重复劳动和繁琐的工作量。
而实际上,我们完全可以把这种繁琐的事情封装起来,这是封装后的所调用存储过程的全部代码:
conn c=new conn(this.txtConn.Text.Trim());
DataTable dt=c.getDataProcedure("MEMBER_TEACHER_GET",new object[] {1001,1000,"t1","教师1",1});
this.dataGrid1.DataSource=dt;
DataTable dt=c.getDataProcedure("MEMBER_TEACHER_GET",new object[] {1001,1000,"t1","教师1",1});
this.dataGrid1.DataSource=dt;
最重只需要传入存储过程的名称和对应的参数即可。
下面分析conn类中getDataProcedure方法的实现。
在传统对存储过程参数的参入下是让存储过程里的参数名和传入参数值一一对应。而实际上,在数据库里,存储过程中的传入参数都是事先写
好,定死的,因此,我们完全可以省去这部分代码的输入,写一个方法getProcParameters让它去数据库里去取得,返回一个ArrayList列表。
其方法如下:
public ArrayList getProcParameters(string proc)
{
System.Data.SqlClient.SqlCommand mycomm=new SqlCommand("sp_sproc_columns",myconn);
DataTable td=new DataTable();
mycomm.CommandType=CommandType.StoredProcedure;
mycomm.Parameters.Add("@procedure_name",(object)proc);
System.Data.SqlClient.SqlDataAdapter myadapter=new SqlDataAdapter(mycomm);
myadapter.Fill(td);
myadapter.Dispose();
ArrayList al=new ArrayList();
for(int i=1;i<td.Rows.Count;i++)
{
al.Add(td.Rows[i][3].ToString());
}
return al;
}
{
System.Data.SqlClient.SqlCommand mycomm=new SqlCommand("sp_sproc_columns",myconn);
DataTable td=new DataTable();
mycomm.CommandType=CommandType.StoredProcedure;
mycomm.Parameters.Add("@procedure_name",(object)proc);
System.Data.SqlClient.SqlDataAdapter myadapter=new SqlDataAdapter(mycomm);
myadapter.Fill(td);
myadapter.Dispose();
ArrayList al=new ArrayList();
for(int i=1;i<td.Rows.Count;i++)
{
al.Add(td.Rows[i][3].ToString());
}
return al;
}
这样,我们就可以在getDataProcedure里我们就可以自动将存储过程的参数和外面传入的参数值一一对应起来。问题就解决了。
public DataTable getDataProcedure(string proc,object[] parms)
{
System.Data.SqlClient.SqlCommand mycomm=new SqlCommand(proc,myconn);
mycomm.CommandType=CommandType.StoredProcedure;
ArrayList al=getProcParameters(proc);
for(int i=0;i<parms.Length;i++)
{
mycomm.Parameters.Add(al[i].ToString(),parms[i]);
}
SqlDataAdapter myAdapter=new SqlDataAdapter();
myAdapter.SelectCommand=mycomm;
DataTable d=new DataTable();
myAdapter.Fill(d);
myAdapter.Dispose();
return d;
}
{
System.Data.SqlClient.SqlCommand mycomm=new SqlCommand(proc,myconn);
mycomm.CommandType=CommandType.StoredProcedure;
ArrayList al=getProcParameters(proc);
for(int i=0;i<parms.Length;i++)
{
mycomm.Parameters.Add(al[i].ToString(),parms[i]);
}
SqlDataAdapter myAdapter=new SqlDataAdapter();
myAdapter.SelectCommand=mycomm;
DataTable d=new DataTable();
myAdapter.Fill(d);
myAdapter.Dispose();
return d;
}
当然,为了提高程序的效率,我们可以改写方法getProcParameters,可以从一个XML里读取存储过程的参数,或者也可以先将所有的参数初始
化到一个数组里去。有兴趣的朋友可以一试。