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

首先来看一下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
  )

 

C#执行存储过程的简化的更多相关文章

  1. Dapper完美兼容Oracle,执行存储过程,并返回结果集。

    Dapper完美兼容Oracle,执行存储过程,并返回结果集. 这个问题,困扰了我整整两天. 刚刚用到Dapper的时候,感觉非常牛掰.特别是配合.net 4.0新特性dynamic,让我生成泛型集合 ...

  2. JAVA使用JDBC技术操作SqlServer数据库执行存储过程

    Java使用JDBC技术操作SqlServer数据库执行存储过程: 1.新建SQLSERVER数据库:java_conn_test 2.新建表:tb_User 3.分别新建三个存储过程: 1>带 ...

  3. Oracle中执行存储过程call和exec区别

    Oracle中执行存储过程call和exec区别 在sqlplus中这两种方法都可以使用: exec pro_name(参数1..); call pro_name(参数1..); 区别: 1. 但是e ...

  4. C#获取执行存储过程的" 返回值"代码

    以下是C#代码: /// <summary> /// 执行存储过程,返回" 返回值" /// </summary> /// <param name=& ...

  5. MyCat 学习笔记 第十三篇.数据分片 之 通过HINT执行存储过程

    1 环境说明 VM 模拟3台MYSQL 5.6 服务器 VM1 192.168.31.187:3307 VM2 192.168.31.212:3307 VM3 192.168.31.150:  330 ...

  6. 原生jdbc执行存储过程

    //定时任务,结转 . //表名 fys_sch_lvyou2 ,存储过程名:fys_sch_lvyou2_carrayover //无参调用:{call insertLine} //有参调用:{ca ...

  7. 0327定时执行--存储过程--dbms_job--dbms_scheduler.create_job

    --oracle job 定时执行 存储过程 --建一张测试表 create table Person( name ), sex ) ); / --创建测试的存储过程 create or replac ...

  8. EF中执行存储过程,获取output返回值

    EF不能直接支持执行存储过程,于是使用转化成执行SQL语句的形式,却怎么也获取不到output的值,折腾的好久,终于解决了,分享下曲折的经历: public int AddVote(int title ...

  9. Oracle创建存储过程、执行存储过程基本语法

    >>>>>>>>>>>>>>>>>>>>>>>>> ...

随机推荐

  1. Flyway, 数据库Schema管理利器

    整天跟数据库打交道的程序员都知道,当数据库的Schema发生改变时是多么痛苦的事情.尤其是一个在不断开发完善的项目,随着需求变化,数据库的schema也会跟着变化,而追踪记录这些变化一向都是费时费力. ...

  2. 几款开源的图形化Redis客户端管理软件

    转载于:http://www.itxuexiwang.com/a/shujukujishu/redis/2016/0216/98.html?1455870209 Redis是一个超精简的基于内存的键值 ...

  3. lua表排序

    对于lua的table排序问题,一般的按照value值来排序,使用table.sort( needSortTable , func)即可(可以根据自己的需要重写func,否则会根据默认来:默认的情形之 ...

  4. 可能是一场很 IN 的技术分享

    从去年的 Swift 到今年的 iOS 9,每一个新的技术.新的设备都"紧紧牵动 iOS 开发者的心". 好在有这样一群开发者,他们乐于第一时间尝试.挑战并分享. 有一类开发者他们 ...

  5. c#设计模式-工厂方法

    一. 工厂方法(Factory Method)模式 工厂方法(FactoryMethod)模式是类的创建模式,其用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中. 工厂方法模式是简单工 ...

  6. iOS-性能优化3

    iOS-性能优化3 UITableView性能优化与卡顿问题 1.最常用的就是cell的重用, 注册重用标识符 如果不重用cell时,每当一个cell显示到屏幕上时,就会重新创建一个新的cell 如果 ...

  7. react6 事件传递参数

    <body><!-- React 真实 DOM 将会插入到这里 --><div id="example"></div> <!- ...

  8. Netty学习四:Channel

    1. Channel Channel是Netty的核心概念之一,它是Netty网络通信的主体,由它负责同对端进行网络通信.注册和数据操作等功能. 1.1 工作原理 如上图所示: 一旦用户端连接成功,将 ...

  9. JS 关于(function( window, undefined ) {})(window)写法的理解

    JS 关于(function( window, undefined ) {})(window)写法的理解 [网络整理] (function( window, undefined ) {})(windo ...

  10. 深入理解javascript函数系列第二篇——函数参数

    × 目录 [1]arguments [2]内部属性 [3]函数重载[4]参数传递 前面的话 javascript函数的参数与大多数其他语言的函数的参数有所不同.函数不介意传递进来多少个参数,也不在乎传 ...