执行一下这个sql:
SELECT B.[name], C.[name] AS [type], B.length, B.isoutparam, B.isnullable FROM sysobjects AS A INNER JOIN"; syscolumns AS B ON A.id = B.id AND A.xtype = 'P' AND A.name = '你的存储过程名' INNER JOIN systypes C ON B.xtype = C.xtype AND C.[name] <> 'sysname' ORDER BY ROW_NUMBER() OVER (ORDER BY B.id), B.isoutparam
看到结果了吧,此时此刻你是否有豁然开朗的感觉?
正是源于此,下面这个类就有了用武之地,从此不用繁琐的配置存储过程参数
using System; using System.Collections; using System.Text; using System.Data.SqlClient; using System.Data; using System.Xml; namespace fnSwordLibrary.DataBase { public class CEx_SqlProcedure { #region 数据成员 private SqlConnection _SqlConnection = null; private String _Procedure = String.Empty; private SqlCommand _SqlCmd = new SqlCommand(); private Hashtable _InputTable = null; // 保存input参数和值 private String _LastError = String.Empty; #endregion #region 构造函数 public CEx_SqlProcedure() { _InputTable = new Hashtable(); _SqlCmd.CommandType = CommandType.StoredProcedure; } public CEx_SqlProcedure(SqlConnection SqlConnection) : this() { this.SqlConnection = SqlConnection; } public CEx_SqlProcedure(String Procedure, SqlConnection SqlConnection) : this() { this.SqlConnection = SqlConnection; this.Procedure = Procedure; } #endregion #region 属性 public String LastError { get { return this._LastError; } } public Object ReturnValue { get { return _SqlCmd.Parameters["RetVal"].Value; } } public SqlConnection SqlConnection { set { this._SqlConnection = value; _SqlCmd.Connection = this._SqlConnection; } } public String Procedure { set { this._Procedure = value; _SqlCmd.CommandText = this._Procedure; } get { return this._Procedure; } } #endregion #region 公共方法 /// <summary> /// 执行存储过程,仅返回是否成功标志 /// </summary> /// <param name="Procedure">存储过程名</param> /// <returns>是否成功标志</returns> public Boolean ExecuteNonQuery(String Procedure) { this.Procedure = Procedure; return ExecuteNonQuery(); } /// <summary> /// 执行存储过程,仅返回是否成功标志 /// </summary> /// <returns>是否成功标志</returns> public Boolean ExecuteNonQuery() { Boolean RetValue = true; // 绑定参数 if (Bindings() == true) { try { // 执行 _SqlCmd.ExecuteNonQuery(); } catch (Exception ex) { _LastError = "execute command error: " + ex.Message; RetValue = false; } } else { RetValue = false; } _InputTable.Clear(); return RetValue; } /// <summary> /// 执行存储过程,返回SqlDataReader /// </summary> /// <param name="Procedure">存储过程名</param> /// <returns>数据库读取行的只进流SqlDataReader</returns> public SqlDataReader ExecuteReader(String Procedure) { this.Procedure = Procedure; return ExecuteReader(); } /// <summary> /// 执行存储过程,返回SqlDataReader /// </summary> /// <returns>数据库读取行的只进流SqlDataReader</returns> public SqlDataReader ExecuteReader() { SqlDataReader sqlReader = null; // 绑定参数 if (Bindings() == true) { try { // 执行 sqlReader = _SqlCmd.ExecuteReader(); } catch (Exception ex) { _LastError = "execute command error: " + ex.Message; } } _InputTable.Clear(); return sqlReader; } /// <summary> /// 执行存储过程,返回SqlDataAdapter /// </summary> /// <param name="Procedure">存储过程名</param> /// <returns>SqlDataAdapter</returns> public SqlDataAdapter ExecuteAdapter(String Procedure) { this.Procedure = Procedure; return ExecuteAdapter(); } /// <summary> /// 执行存储过程,返回SqlDataAdapter /// </summary> /// <returns>SqlDataAdapter</returns> public SqlDataAdapter ExecuteAdapter() { SqlDataAdapter sqlAdapter = null; // 绑定参数 if (Bindings() == true) { try { // 执行 sqlAdapter = new SqlDataAdapter(_SqlCmd); } catch (Exception ex) { _LastError = "execute command error: " + ex.Message; } } _InputTable.Clear(); return sqlAdapter; } /// <summary> /// 获取output的键值 /// </summary> /// <param name="Output">output键名称</param> /// <returns>output键值</returns> public Object GetOutputValue(String Output) { return _SqlCmd.Parameters[Output].Value; } /// <summary> /// 设置Input参数值 /// </summary> /// <param name="Key">参数名</param> /// <param name="Value">参数值</param> public void SetInputValue(String Key, Object Value) { if (Key == null) { return; } if (!Key.StartsWith("@")) { Key = "@" + Key; } if (_InputTable.ContainsKey(Key)) { _InputTable[Key] = Value; } else { _InputTable.Add(Key, Value); } } /// <summary> /// 获取已设置的Input参数值 /// 注:存储过程被成功执行后, Input参数被清空 /// </summary> /// <param name="Key">参数名</param> /// <returns>参数值</returns> public Object GetInputValue(String Key) { if (Key == null) { return null; } if (!Key.StartsWith("@")) { Key = "@" + Key; } if (_InputTable.ContainsKey(Key)) { return _InputTable[Key]; } else { return null; } } #endregion #region 私有方法 /// <summary> /// 给SqlCommand对象绑定参数 /// </summary> /// <returns>是否成功标志</returns> private Boolean Bindings() { _SqlCmd.Parameters.Clear(); XmlReader sqlXmlReader = GetParameters(); try { while (sqlXmlReader.Read()) { try { if (Byte.Parse(sqlXmlReader["isoutparam"]) == 1) { // 绑定output参数 _SqlCmd.Parameters.Add(sqlXmlReader["name"], GetSqlDbType(sqlXmlReader["type"]), Int32.Parse(sqlXmlReader["length"])).Direction = ParameterDirection.Output; } else { // 绑定input参数,并赋值 _SqlCmd.Parameters.Add(sqlXmlReader["name"], GetSqlDbType(sqlXmlReader["type"]), Int32.Parse(sqlXmlReader["length"])).Value = this.GetInputValue(sqlXmlReader["name"]); /* * 不必担心赋值的ParametersValue类型问题,SqlParameter.Value是object类型,自动转换 */ } } catch (Exception ex) { _LastError = sqlXmlReader["name"] + " parameter error: " + ex.Message; return false; } } // 绑定返回值 _SqlCmd.Parameters.Add("RetVal", SqlDbType.Variant).Direction = ParameterDirection.ReturnValue; } catch (Exception ex) { _LastError = "binding parameter error: " + ex.Message; return false; } return true; } /// <summary> /// 由存储过程名, 取包含参数的XmlReader /// </summary> /// <param name="Procedure">存储过程名</param> /// <returns>包含参数的XmlReader</returns> private XmlReader GetParameters() { String sqlStr = "SELECT B.[name], C.[name] AS [type], B.length, B.isoutparam, B.isnullable"; sqlStr += " FROM sysobjects AS A INNER JOIN"; sqlStr += " syscolumns AS B ON A.id = B.id AND A.xtype = 'P' AND A.name = '" + _Procedure + "' INNER JOIN"; sqlStr += " systypes C ON B.xtype = C.xtype AND C.[name] <> 'sysname'"; sqlStr += " ORDER BY ROW_NUMBER() OVER (ORDER BY B.id), B.isoutparam"; sqlStr += " FOR XML RAW"; SqlCommand sqlCmd = new SqlCommand(sqlStr, _SqlConnection); // <row name="Action" type="varchar" length="50" isoutparam="0" isnullable="1" /> XmlReader sqlXmlReader = null; try { sqlXmlReader = sqlCmd.ExecuteXmlReader(); } catch (Exception ex) { if (sqlXmlReader != null) sqlXmlReader.Close(); sqlXmlReader = null; _LastError = "get parameters error: " + ex.Message; } finally { sqlCmd.Dispose(); sqlCmd = null; } return sqlXmlReader; } protected internal static SqlDbType GetSqlDbType(String TypeName) { switch (TypeName) { case "image": return SqlDbType.Image; case "text": return SqlDbType.Text; case "uniqueidentifier": return SqlDbType.UniqueIdentifier; case "tinyint": return SqlDbType.TinyInt; case "smallint": return SqlDbType.SmallInt; case "int": return SqlDbType.Int; case "smalldatetime": return SqlDbType.SmallDateTime; case "real": return SqlDbType.Real; case "money": return SqlDbType.Money; case "datetime": return SqlDbType.DateTime; case "float": return SqlDbType.Float; case "sql_variant": return SqlDbType.Variant; case "ntext": return SqlDbType.NText; case "bit": return SqlDbType.Bit; case "decimal": return SqlDbType.Decimal; case "numeric": return SqlDbType.Decimal; case "smallmoney": return SqlDbType.SmallMoney; case "bigint": return SqlDbType.BigInt; case "varbinary": return SqlDbType.VarBinary; case "varchar": return SqlDbType.VarChar; case "binary": return SqlDbType.Binary; case "char": return SqlDbType.Char; case "timestamp": return SqlDbType.Timestamp; case "nvarchar": return SqlDbType.NVarChar; case "nchar": return SqlDbType.NChar; case "xml": return SqlDbType.Xml; default: return SqlDbType.Variant; } } #endregion } }
// 调用示例 // 设置连接对象 CEx_SqlProcedure SqlProcedure = new CEx_SqlProcedure("doArticle", SqlConnection); // 填充参数 SqlProcedure.SetInputValue("@Action", "GetArticles"); SqlProcedure.SetInputValue("@Keywords", Keyword); SqlProcedure.SetInputValue("@SortID", Sort); SqlProcedure.SetInputValue("@CurPage", CurPage); SqlProcedure.SetInputValue("@PageSize", PageSize); // 执行 SqlProcedure.ExecuteAdapter().Fill(sqlDataSet); // 取output和返回值(为了简洁,我直接用object) object MaxPage = SqlProcedure.GetOutputValue("@MaxPage"); object ReturnValue = SqlProcedure.ReturnValue;