zoukankan      html  css  js  c++  java
  • C#执行存储过程的简化

    下面的方法是我在实际开发中摸索出来的,可以在很大程度上简化调用存储过程的代码。

    首先来看一下C#调用存储过程的一般过程:
    1、打开数据库连接SqlConnection;
    2、生成一个SqlCommand;
    3、向命令对象填充参数;
    4、执行存储过程;
    5、关闭连接;
    6、其他操作。

    我这里讲的主要是简化第3步操作,最终在调用存储过程的时候只需要传递存储过程的名字和相应的参数值。调用示例如下:
            dbAccess.run("p_am_deleteFile", new object[]{LoginId, Request.UserHostAddress, fileId});

    由于在填充参数的时候必须要两个值,一个是参数的名字,一个是参数的值。参数值是由外部传入的,不用考虑;而参数名称是和存储过程相关的东西,应该可以由存储过程名称来确定而不用每次调用的时候写上一遍。对于这个问题,如果能将存储过程的参数保存到一个全局的地方,那么在调用存储过程的时候只要能根据存储过程的名字去索引就可以了。具体实现的时候我是将这些信息保存在数据库访问组件里面,采用名字/值对的方式。代码如下:
    public class InfoTable : NameObjectCollectionBase
    {
       public object this[string key]  
       {
        get  
        {
         return(this.BaseGet(key));
        }
        set  
        {
         this.BaseSet(key, value);
        }
       }
    }
    protected static InfoTable procInfoTable = new InfoTable();
    public static InfoTable ProcInfoTable
    {
       get
       {
        return procInfoTable;
       }
    }

    这样的话,在实际调用存储过程的时候就只需要去查这张表就可以知道存储过程的参数名了。实现代码如下:
    public DataTable run(string procName, object[] parms, ref int retValue)
    {
     string[] paramInfo = (string[])(procInfoTable[procName]);
     if (paramInfo == null)
     {
      ErrorInfo.setErrorInfo("未取得" + procName + "的参数!");
      return null;
     }

     bool bOpened = (dbConn.State == ConnectionState.Open);
     if (!bOpened && !connect())
     {
      return null;
     }

     DataSet ds = new DataSet();    
     try
     {
      SqlCommand cmd = new SqlCommand(procName, dbConn);
      cmd.CommandType = CommandType.StoredProcedure;

      for (int i = 0; i < parms.Length && i < paramInfo.Length; ++i)
      {
       cmd.Parameters.Add(new SqlParameter(paramInfo[i], parms[i]));
      }

      SqlParameter parmsr = new SqlParameter("return", SqlDbType.Int);
      parmsr.Direction = ParameterDirection.ReturnValue;
      cmd.Parameters.Add(parmsr);

      SqlDataAdapter adp = new SqlDataAdapter(cmd);
      adp.Fill(ds);
      retValue = (int)(cmd.Parameters["return"].Value);
     }
     catch (Exception ex)
     {
      ErrorInfo.setErrorInfo(ex.Message);

      retValue = -1;
     }

     if (!bOpened)
      close();

     if (ds.Tables.Count > 0)
      return ds.Tables[0];
     else
      return null;
    }

    可以看出,每个存储过程的参数列表存储为了一个string[]。接下来的工作就是将系统里头许许多多的存储过程的参数填充到表ProcInfoTable中。我所用的数据库是Sql Server 2000,下面给出一个存储过程来解决这个烦人的问题:
    create PROCEDURE dbo.p_am_procInfo
    (
     @procName t_str64 --存储过程的名字
    )
    AS
    begin
     set nocount on

     if @procName = '' begin
      select name as procName
      from sysobjects
      where substring(sysobjects.name, 1, 5) = 'p_am_'
     end
     else begin
      select 
       syscolumns.name as paramName
      from sysobjects, syscolumns
      where sysobjects.id = syscolumns.id
       and sysobjects.name = @procName
      order by colid
     end
     
    end

    这个存储过程有两个作用,在没有传递存储过程的名字的时候,该存储过程返回所有以”p_am_”开头的存储过程的名字;在传入了相应的存储过程名字后,该存储过程返回该存储过程的参数列表。这样一来,我们在程序开始的地方就可以将系统里的存储过程参数列表取出来并保存到数据库访问组件的ProcInfoTable属性中了。具体代码如下:
    span.DBAccess dbAccess = new span.DBAccess();

    //
    //构造取存储过程的参数表
    //
    span.DBAccess.ProcInfoTable["p_am_procInfo"] = new string[]{"@procName"};

    //
    //取得其他存储过程列表
    //
    DataTable dt = dbAccess.run("p_am_procInfo", new object[]{""});
    if (dt == null || dt.Rows.Count <= 0)
    {
     return;
    }

    //
    //取得其他存储过程的参数表
    //
    foreach (DataRow dr in dt.Rows)
    {
     DataTable dtParams = dbAccess.run("p_am_procInfo", new object[]{dr["procName"]});
     if (dtParams != null)
     {
      string[] paramInfo = new string[dtParams.Rows.Count];
      for (int i = 0; i < dtParams.Rows.Count; ++i)
       paramInfo[i] = dtParams.Rows[i]["paramName"].ToString();

      span.DBAccess.ProcInfoTable[dr["procName"].ToString()] = paramInfo;
     }
    }

    至此,全部技术细节介绍完毕。另外,数据库访问对象的几个接口函数也一并给出:

    //打开、关闭数据库连接
    public bool connect(string strConn)
    public bool connect()
    public bool close()

    //执行SQL命令(只有一个int返回)
    public int exec(string procName, object[] parms)
    public int exec(string sql)

    //运行(返回一个DataTable)
    public DataTable run(string procName, object[] parms, ref int retValue)
    public DataTable run(string procName, object[] parms)
    public DataTable run(string sql)

    //分页查询(页号从1开始,返回一个DataTable)
    public DataTable pageQuery
      (
       string selectCmd,
       int pageSize,
       int pageNumber
      )

     
  • 相关阅读:
    DotNet中的迭代模式和组合模式
    能以可视化方式编辑滤镜效果的Image控件
    自定义ExtenderControl实现服务器控件可拖放
    股票交易费及利润计算器
    用ajax library的客户端脚本实现无刷新分页
    实现html转Xml
    oracle10g主机身份证明错误的解决办法
    创建ASP.NET AJAX客户端组件实现验证控件的toolTip式错误提示
    可分页的Repeater控件
    数据结构趣题——约瑟夫环
  • 原文地址:https://www.cnblogs.com/sosoft/p/3451113.html
Copyright © 2011-2022 走看看