存储过程调用

# SQL语句:先编译后执行

存储过程(Stored Procedure):

  一组可编程的函数,是为了完成特定功能的SQL语句集,经编译创建并保存在数据库中,用户可通过指定存储过程的名字并给定参数(需要时)来调用执行。

优点(为什么要用存储过程?):

  ①将重复性很高的一些操作,封装到一个存储过程中,简化了对这些SQL的调用

  ②批量处理:SQL+循环,减少流量,也就是“跑批”

  ③统一接口,确保数据的安全

相对于oracle数据库来说,MySQL的存储过程相对功能较弱,使用较少。

 

一、存储过程的创建和调用

  >存储过程就是具有名字的一段代码,用来完成一个特定的功能。

  >创建的存储过程保存在数据库的数据字典中。

  public DataSet Query(string procName, ref int Total, SqlParameter[] sqlParameters)
        {
            DataSet set = new DataSet();
            using (SqlConnection conn = new SqlConnection(con))
            {
                conn.Open();
                using (SqlCommand comm = new SqlCommand(procName, conn))
                {
                    comm.Parameters.AddRange(sqlParameters);
                    comm.CommandType = CommandType.StoredProcedure;
                    SqlDataAdapter adapter = new SqlDataAdapter(comm);
                    adapter.Fill(set);
                    Total = int.Parse(comm.Parameters["@Total"].Value.ToString());
                }
            }
            return set;
        }

 

下面这个例子展示如何在ADO.NET调用存储过程。我只选择了一种方式,说实话不太喜欢多样化的方式去处理问题,这种发散式的做法在编程中似乎没有必要。选择自己喜欢的一种方式。

这里SQL Server有一个样本数据库Northwind.

以Northwind里的Region表为例:

Region表有2个字段:

  • RegionID, int 主键
  • RegionDescription, nchar(50)

写以下几个存储过程:

RegionUpdate: 多个参数

CREATE PROCEDURE RegionUpdate(@RegionID INTEGER, @RegionDescription NCHAR(50))
AS
SET NOCOUNT OFF
UPDATE Region
SET RegionDescription = @RegionDescription
WHERE RegionID = @RegionID
GO

RegionDelete 一个参数

CREATE PROCEDURE RegionUpdate(@RegionID INTEGER)
AS
SET NOCOUNT OFF
DELETE FROM Region
WHERE RegionID = @RegionID
GO

RegionInsert 带返回参数

CREATE PROCEDURE RegionInsert(@RegionDescription NCHAR(50), @RegionID INTEGER OUTPUT)
AS
SET NOCOUNT OFF
SELECT @RegionID = MAX(RegionID) + 1 
FROM Region
INSERT INTO Region VALUES(@RegionID, @RegionDescription)
GO

 

public DataTable GetPagingDept(ref int Total, int pageSize, int pageNumber, string where, string field)
        {
            SqlParameter[] sqlParameters = new SqlParameter[]
                {
new SqlParameter{ ParameterName="@table",Value=" Shopping ",SqlDbType=SqlDbType.NVarChar,Direction= ParameterDirection.Input,Size=200},
new SqlParameter{ ParameterName="@field",Value=field,SqlDbType=SqlDbType.NVarChar,Direction= ParameterDirection.Input,Size=2000},
new SqlParameter{ ParameterName="@where",Value=where,SqlDbType=SqlDbType.NVarChar,Direction= ParameterDirection.Input,Size=2000},
new SqlParameter{ ParameterName="@order",Value=" Id ",SqlDbType=SqlDbType.NVarChar,Direction= ParameterDirection.Input,Size=200},
new SqlParameter{ ParameterName="@pageSize",Value=pageSize,SqlDbType=SqlDbType.Int,Direction= ParameterDirection.Input},
new SqlParameter{ ParameterName="@pageNumber",Value=pageNumber,SqlDbType=SqlDbType.Int,Direction= ParameterDirection.Input},
new SqlParameter{ ParameterName="@Total",SqlDbType=SqlDbType.Int,Direction= ParameterDirection.Output},
                };
            return db.Query("[SP_UserInfo]", ref Total, sqlParameters).Tables[0];
        }

 

我假设我们已经对IDataParameter对象进行了封装,我想对它简单的封装基本也都能满足日常要求了。一般都是根据当前项目链接数据库的类型字符串进行判断,然后生成相对应如:SqlParameter、OracleParameter、OleDbParameter等等,可能还包括一些开源的数据库扩展框架中的对象,这里的创建工厂可能是抽象工厂,当然方法很多种,实现效果就行。[王清培版权所有,转载请给出署名]
对其简单的封装我们在使用的时候需要使用工厂方法创建IDataParameter数组,如:

  

一般性的封装基本都这样或者在IDataParameterFactory.CreateDbDataParameter(Entity)中加入根据实体的属性动态的创建IDataParameter[]对象,如果你的创建始终是使用反射的话那么将是不可取的。有兴趣的朋友可以参见本人的另一篇文章“利用抽象、多态实现无反射的绿色环保ORM框架”对实体的使用如果不能摆脱反射,那么在以后的基础库扩展中将面临着很多性能问题,这里需三思。

由于很少存储过程的参数名称都是对应的实体的属性名称,这种对应关系很难做到,或者说是做到的话需要DBA花点时间呢,在命名上也是个约束。
如果存储过程有N个参数的话我们需要对照数据库设计文档来编写IDictionary项,在一般的项目中都将复杂的业务逻辑封装在存储过程中实现,所以存储过程的数量也是不少的。这样一来也算是一个比较浪费时间的工作。
那么如果减少编码量,让存储过程的调用变的简单,而且对用户来说是透明的?
public IHttpActionResult Show(int pageSize, int pageNumber,string name)
        {
            int Total = 0;
            if (!string.IsNullOrEmpty(name))
            {
                Total = 0;
                name = " Sho_Name like '%" + name + "%'";
            }
            else
            {
                name = " 1=1 ";
            }
                    
            DataTable tb = bll.GetPagingDept(ref Total, pageSize, pageNumber, name, " * ");
            PagingModel<DataTable> paging = new PagingModel<DataTable> { tb = tb, Total = Total };
            return Ok(paging);
            
        }

 

posted @ 2020-06-10 12:41  牛头梗国王  阅读(314)  评论(0)    收藏  举报