⭐️ Furion v4 版本支持【所有历史版本】无缝升级,一套代码兼容 .NET 5+ ⭐️
Skip to main content

9.13 存储过程操作

温馨提示

推荐使用 《9.17 Sql 高级代理》代替本章节功能。Sql 高级代理 能够提供更容易且更易维护的方式。

9.13.1 关于存储过程

引用百度百科:

存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的 SQL 语句集,它存储在数据库中,一次编译后永久有效,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。

存储过程是数据库中的一个重要对象。在数据量特别庞大的情况下利用存储过程能达到倍速的效率提升。

简单来说,存储过程就是关系型数据库中(Sqlite 除外)中编写逻辑的函数/方法,通过这种方式,可以将 sql 编译缓存起来,大大提高存储过程的执行效率。

这里不讨论存储过程的优缺点。

9.13.2.0 支持存储过程的数据库

SqlServerSqliteCosmosInMemoryDatabaseMySqlPostgreSQLOracleFirebirdDm

9.13.2 存储过程使用

Furion 框架中提供了多种存储过程操作方式:

  • ISqlRepositorySql 操作仓储,可通过 依赖注入
  • ISqlDispatchProxySql 代理方式(高级用法,推荐)
  • 通过任意实体仓储操作:personRepository.SqlProcedureQuery(procName)
  • 通过字符串拓展方法:procName.SqlProcedureQuery()
  • 通过 repository.Sql().SqlProcedureQuery() 方式

9.13.2.1 初始化方式

using Furion.DatabaseAccessor;using Furion.DynamicApiController;namespace Furion.Application{    [DynamicApiController]    public class SqlService    {        private ISqlRepository _sqlRepository;        public SqlService(ISqlRepository sqlRepository)        {            _sqlRepository = sqlRepository;        }    }}

9.13.2.2 返回 DataTable

// ISqlRepository 方法var dataTable = _sqlRepository.SqlProcedureQuery("proc_GetPersons");// ISqlDispatchProxy 方式var dataTable = _sqlExecuteProxy.GetPersons();  // 推荐方式// 实体仓储方式var dataTable = _personRepository.SqlProcedureQuery("proc_GetPersons");// IRepository 非泛型方式var dataTable = _repository.Sql().SqlProcedureQuery("proc_GetPersons");// 变态懒人方式,直接通过存储过程名执行var dataTable = "proc_GetPersons".SqlProcedureQuery();
关于异步

Furion 框架每一个数据库操作都支持异步方式,由于篇幅有限,就不列举异步方式了。

9.13.2.3 返回 DataSet

// ISqlRepository 方法var dataSet = _sqlRepository.SqlProcedureQueries("proc_GetPersons");// ISqlDispatchProxy 方式var dataSet = _sqlExecuteProxy.GetPersons();  // 推荐方式// 实体仓储方式var dataSet = _personRepository.SqlProcedureQueries("proc_GetPersons");// IRepository 非泛型方式var dataSet = _repository.Sql().SqlProcedureQueries("proc_GetPersons");// 变态懒人方式,直接通过存储过程名执行var dataSet = "proc_GetPersons".SqlProcedureQueries();
关于异步

Furion 框架每一个数据库操作都支持异步方式,由于篇幅有限,就不列举异步方式了。

9.13.2.4 返回 List<T>

// ISqlRepository 方法var list = _sqlRepository.SqlProcedureQuery<Person>("proc_GetPersons");// ISqlDispatchProxy 方式var list = _sqlExecuteProxy.GetPersons();  // 推荐方式// 实体仓储方式var list = _personRepository.SqlProcedureQuery<Person>("proc_GetPersons");// IRepository 非泛型方式var list = _repository.Sql().SqlProcedureQuery<Person>("proc_GetPersons");// 变态懒人方式,直接通过存储过程名执行var list = "proc_GetPersons".SqlProcedureQuery<Person>();
关于异步

Furion 框架每一个数据库操作都支持异步方式,由于篇幅有限,就不列举异步方式了。

9.13.2.5 返回 Tuple<T1,...T8>

Furion 框架大大利用了 Tuple 的特性,将返回多个结果集转成 Tuple<T1,...T8> 类型

// ISqlRepository 方法// 返回一个结果集var list1 = _sqlRepository.SqlProcedureQueries<T1>("proc_GetPersons");// 返回两个结果集var (list1, list2) = _sqlRepository.SqlProcedureQueries<T1,T2>("proc_GetPersons");// 返回三个结果集var (list1, list2, list3) = _sqlRepository.SqlProcedureQueries<T1,T2,T3>("proc_GetPersons");// 返回四个结果集var (list1, list2, list3, list4) = _sqlRepository.SqlProcedureQueries<T1,T2,T3,T4>("proc_GetPersons");// 返回五个结果集var (list1, list2, list3, list4, list5) = _sqlRepository.SqlProcedureQueries<T1,T2,T3,T4,T5>("proc_GetPersons");// 返回六个结果集var (list1, list2, list3, list4, list5, list6) = _sqlRepository.SqlProcedureQueries<T1,T2,T3,T4,T5,T6>("proc_GetPersons");// 返回七个结果集var (list1, list2, list3, list4, list5, list6, list7) = _sqlRepository.SqlProcedureQueries<T1,T2,T3,T4,T5,T6,T7>("proc_GetPersons");// 返回八个结果集var (list1, list2, list3, list4, list5, list6, list7, list8) = _sqlRepository.SqlProcedureQueries<T1,T2,T3,T4,T5,T6,T7,T8>("proc_GetPersons");// ==================================// ISqlDispatchProxy 方式,推荐方式,自动处理多个结果集// 返回一个结果集var list1 = _sqlRepository.GetDatas();// 返回两个结果集var (list1, list2) = _sqlRepository.GetDatas();// 返回三个结果集var (list1, list2, list3) = _sqlRepository.GetDatas();// 返回四个结果集var (list1, list2, list3, list4) = _sqlRepository.GetDatas();// 返回五个结果集var (list1, list2, list3, list4, list5) = _sqlRepository.GetDatas();// 返回六个结果集var (list1, list2, list3, list4, list5, list6) = _sqlRepository.GetDatas();// 返回七个结果集var (list1, list2, list3, list4, list5, list6, list7) = _sqlRepository.GetDatas();// 返回八个结果集var (list1, list2, list3, list4, list5, list6, list7, list8) = _sqlRepository.GetDatas();// ==================================// 实体仓储方式// 返回一个结果集var list1 = _personRepository.SqlProcedureQueries<T1>("proc_GetPersons");// 返回两个结果集var (list1, list2) = _personRepository.SqlProcedureQueries<T1,T2>("proc_GetPersons");// 返回三个结果集var (list1, list2, list3) = _personRepository.SqlProcedureQueries<T1,T2,T3>("proc_GetPersons");// 返回四个结果集var (list1, list2, list3, list4) = _personRepository.SqlProcedureQueries<T1,T2,T3,T4>("proc_GetPersons");// 返回五个结果集var (list1, list2, list3, list4, list5) = _personRepository.SqlProcedureQueries<T1,T2,T3,T4,T5>("proc_GetPersons");// 返回六个结果集var (list1, list2, list3, list4, list5, list6) = _personRepository.SqlProcedureQueries<T1,T2,T3,T4,T5,T6>("proc_GetPersons");// 返回七个结果集var (list1, list2, list3, list4, list5, list6, list7) = _personRepository.SqlProcedureQueries<T1,T2,T3,T4,T5,T6,T7>("proc_GetPersons");// 返回八个结果集var (list1, list2, list3, list4, list5, list6, list7, list8) = _personRepository.SqlProcedureQueries<T1,T2,T3,T4,T5,T6,T7,T8>("proc_GetPersons");// ==================================// IRepository 非泛型方式// 返回一个结果集var list1 = _repository.Sql().SqlProcedureQueries<T1>("proc_GetPersons");// 返回两个结果集var (list1, list2) = _repository.Sql().SqlProcedureQueries<T1,T2>("proc_GetPersons");// 返回三个结果集var (list1, list2, list3) = _repository.Sql().SqlProcedureQueries<T1,T2,T3>("proc_GetPersons");// 返回四个结果集var (list1, list2, list3, list4) = _repository.Sql().SqlProcedureQueries<T1,T2,T3,T4>("proc_GetPersons");// 返回五个结果集var (list1, list2, list3, list4, list5) = _repository.Sql().SqlProcedureQueries<T1,T2,T3,T4,T5>("proc_GetPersons");// 返回六个结果集var (list1, list2, list3, list4, list5, list6) = _repository.Sql().SqlProcedureQueries<T1,T2,T3,T4,T5,T6>("proc_GetPersons");// 返回七个结果集var (list1, list2, list3, list4, list5, list6, list7) = _repository.Sql().SqlProcedureQueries<T1,T2,T3,T4,T5,T6,T7>("proc_GetPersons");// 返回八个结果集var (list1, list2, list3, list4, list5, list6, list7, list8) = _repository.Sql().SqlProcedureQueries<T1,T2,T3,T4,T5,T6,T7,T8>("proc_GetPersons");// ==================================// 变态懒人方式,直接通过存储过程名执行// 返回一个结果集var list1 = "proc_GetPersons".SqlProcedureQueries<T1>();// 返回两个结果集var (list1, list2) = "proc_GetPersons".SqlProcedureQueries<T1,T2>();// 返回三个结果集var (list1, list2, list3) = "proc_GetPersons".SqlProcedureQueries<T1,T2,T3>();// 返回四个结果集var (list1, list2, list3, list4) = "proc_GetPersons".SqlProcedureQueries<T1,T2,T3,T4>();// 返回五个结果集var (list1, list2, list3, list4, list5) = "proc_GetPersons".SqlProcedureQueries<T1,T2,T3,T4,T5>();// 返回六个结果集var (list1, list2, list3, list4, list5, list6) = "proc_GetPersons".SqlProcedureQueries<T1,T2,T3,T4,T5,T6>();// 返回七个结果集var (list1, list2, list3, list4, list5, list6, list7) = "proc_GetPersons".SqlProcedureQueries<T1,T2,T3,T4,T5,T6,T7>();// 返回八个结果集var (list1, list2, list3, list4, list5, list6, list7, list8) = "proc_GetPersons".SqlProcedureQueries<T1,T2,T3,T4,T5,T6,T7,T8>();
关于异步

Furion 框架每一个数据库操作都支持异步方式,由于篇幅有限,就不列举异步方式了。

9.13.2.6 返回 单行单列 object

// ISqlRepository 方法var value = _sqlRepository.SqlProcedureScalar("proc_GetName");// ISqlDispatchProxy 方式var value = _sqlExecuteProxy.GetName();  // 推荐方式// 实体仓储方式var value = _personRepository.SqlProcedureScalar("proc_GetName");// IRepository 非泛型方式var value = _repository.Sql().SqlProcedureScalar("proc_GetName");// 变态懒人方式,直接通过存储过程名执行var value = "proc_GetName".SqlProcedureScalar();
关于异步

Furion 框架每一个数据库操作都支持异步方式,由于篇幅有限,就不列举异步方式了。

9.13.2.7 返回 单行单列 <T>

// ISqlRepository 方法var value = _sqlRepository.SqlProcedureScalar<string>("proc_GetName");// ISqlDispatchProxy 方式var value = _sqlExecuteProxy.GetName();  // 推荐方式// 实体仓储方式var value = _personRepository.SqlProcedureScalar<string>("proc_GetName");// IRepository 非泛型方式var value = _repository.Sql().SqlProcedureScalar<string>("proc_GetName");// 变态懒人方式,直接通过存储过程名执行var value = "proc_GetName".SqlProcedureScalar<string>();
关于异步

Furion 框架每一个数据库操作都支持异步方式,由于篇幅有限,就不列举异步方式了。

9.13.2.8 执行但无返回

// ISqlRepository 方法_sqlRepository.SqlProcedureNonQuery("proc_UpdateData");// ISqlDispatchProxy 方式_sqlExecuteProxy.UpdateData();  // 推荐方式// 实体仓储方式_personRepository.SqlProcedureNonQuery("proc_UpdateData");// IRepository 非泛型方式_repository.Sql().SqlProcedureNonQuery("proc_UpdateData");// 变态懒人方式,直接通过存储过程名执行"proc_UpdateData".SqlProcedureNonQuery();
关于异步

Furion 框架每一个数据库操作都支持异步方式,由于篇幅有限,就不列举异步方式了。

9.13.3 执行复杂存储过程

在存储过程中,有一种例子非常复杂,那就是既有 INPUT 参数,又有 OUTPUT 参数,还有 RETURN 参数,同时还输出 结果集 💥,如:

CREATE PROC PROC_Output    @Id INT,    // 输入参数    @Name NVARCHAR(32) OUTPUT,  // 输出参数,还带长度    @Age INT OUTPUT // 输出参数ASBEGIN    SET @Name = 'Furion Output';    // 输出结果集    SELECT *    FROM dbo.Test    WHERE Id > @Id;    // 输出结果集    SELECT TOP 10           *    FROM dbo.Test;    SET @Age = 27;    // 带 RETURN 返回    RETURN 10;END;

9.13.3.1 创建参数模型

using Furion.DatabaseAccessor;using System.Data;namespace Furion.Application{    public class ProcOutputModel    {        public int Id { get; set; } // 输入参数        [DbParameter(ParameterDirection.Output, Size = 32)]        public string Name { get; set; }    // 输出参数        [DbParameter(ParameterDirection.Output)]        public int Age { get; set; }    // 输出参数        [DbParameter(ParameterDirection.ReturnValue)]        public int ReturnValue { get; set; }    // 返回值    }}

9.13.3.2 执行复杂存储过程

  • DataSet 方式
// ISqlRepository 方法ProcedureOutputResult result = _sqlRepository.SqlProcedureOutput("proc_Complex", new ProcOutputModel{});// ISqlDispatchProxy 方式ProcedureOutputResult result = _sqlExecuteProxy.Complex(new ProcOutputModel{});  // 推荐方式// 实体仓储方式ProcedureOutputResult result = _personRepository.SqlProcedureOutput("proc_Complex", new ProcOutputModel{});// IRepository 非泛型方式ProcedureOutputResult result = _repository.Sql().SqlProcedureOutput("proc_Complex", new ProcOutputModel{});// 变态懒人方式,直接通过存储过程名执行ProcedureOutputResult result = "proc_Complex".SqlProcedureOutput(new ProcOutputModel{});
// 获取 OUTPUT 参数值var outputs = result.OutputValues;// 获取 RETURN 返回值var reval = result.ReturnValue;// 获取返回结果集var dataSet = result.Result;
  • Tuple<T1,...T8> 方式
// ISqlRepository 方法ProcedureOutputResult<(List<Test>, List<Test>)> result = _sqlRepository.SqlProcedureOutput<(List<Test>, List<Test>)>("proc_Complex", new ProcOutputModel{});// ISqlDispatchProxy 方式ProcedureOutputResult<(List<Test>, List<Test>)> result = _sqlExecuteProxy.Complex(new ProcOutputModel{});  // 推荐方式// 实体仓储方式ProcedureOutputResult<(List<Test>, List<Test>)> result = _personRepository.SqlProcedureOutput<(List<Test>, List<Test>)>("proc_Complex", new ProcOutputModel{});// IRepository 非泛型方式ProcedureOutputResult<(List<Test>, List<Test>)> result = _repository.Sql().SqlProcedureOutput<(List<Test>, List<Test>)>("proc_Complex", new ProcOutputModel{});// 变态懒人方式,直接通过存储过程名执行ProcedureOutputResult<(List<Test>, List<Test>)> result = "proc_Complex".SqlProcedureOutput<(List<Test>, List<Test>)>(new ProcOutputModel{});
// 获取 OUTPUT 参数值var outputs = result.OutputValues;// 获取 RETURN 返回值var reval = result.ReturnValue;// 获取返回结果集var (list1,list2) = result.Result;
关于异步

Furion 框架每一个数据库操作都支持异步方式,由于篇幅有限,就不列举异步方式了。

9.13.3 关于 [DbParameter]

[DbParameter] 特性是用来标注 Sql函数存储过程 参数的,可配置属性:

  • Direction:设置参数方向,ParameterDirection 枚举类型,默认 ParameterDirection.Input
  • DbType:设置参数类型,DbType 枚举类型,无默认
  • Size:设置参数长度的,int 类型

其中 Direction 属性是默认构造函数参数。

9.13.4 关于 ProcedureOutputResult

ProcedureOutputResultProcedureOutputResult<TResult> 是复杂存储过程执行返回模型类,有以下属性:

  • OutputValues:多个输出值,ProcedureOutputValue 类型
  • ReturnValue:返回值,object 类型
  • Result:结果集,非泛型版本是 DataSet类型,否则是 泛型类型

9.13.5 存储过程参数

所有 sql 参数都支持四种方式:

  • DbParameter[]:数组类型
  • new {}:匿名类型
  • new Class{}:强类型类型(支持复杂存储过程参数)
  • Dictionary<string,object> 类型

9.13.6 反馈与建议

与我们交流

给 Furion 提 Issue

演练场