9.14 存储过程操作
推荐使用 《9.18 Sql 高级代理》代替本章节功能。Sql 高级代理
能够提供更容易且更易维护的方式。
9.14.1 关于存储过程
引用百度百科:
存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的 SQL 语句集,它存储在数据库中,一次编译后永久有效,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。
存储过程是数据库中的一个重要对象。在数据量特别庞大的情况下利用存储过程能达到倍速的效率提升。
简单来说,存储过程就是关系型数据库中(Sqlite
除外)中编写逻辑的函数/方法,通过这种方式,可以将 sql
编译缓存起来,大大提高存储过程的执行效率。
这里不讨论存储过程的优缺点。
9.14.2.0 支持存储过程的数据库
SqlServer | Sqlite | Cosmos | InMemoryDatabase | MySql | PostgreSQL | Oracle | Firebird | Dm |
---|---|---|---|---|---|---|---|---|
✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
9.14.2 存储过程使用
Furion
框架中提供了多种存储过程操作方式:
ISqlRepository
:Sql
操作仓储,可通过依赖注入
ISqlDispatchProxy
:Sql
代理方式(高级用法,推荐)- 通过任意实体仓储操作:
personRepository.SqlProcedureQuery(procName)
- 通过字符串拓展方法:
procName.SqlProcedureQuery()
- 通过
repository.Sql().SqlProcedureQuery()
方式
9.14.2.1 初始化方式
- ISqlRepository
- ISqlDispatchProxy
- 实体仓储方式
- 字符串拓展方式
using Furion.DatabaseAccessor;
using Furion.DynamicApiController;
namespace Furion.Application
{
[DynamicApiController]
public class SqlService
{
private ISqlRepository _sqlRepository;
public SqlService(ISqlRepository sqlRepository)
{
_sqlRepository = sqlRepository;
}
}
}
using Furion.Core;
using Furion.DatabaseAccessor;
using System.Collections.Generic;
namespace Furion.Application
{
public interface ISqlExecuteProxy : ISqlDispatchProxy
{
[SqlProcedure("proc_GetPersons")]
List<Person> GetPersons(string keyword);
}
}
using Furion.DatabaseAccessor;
using Furion.DynamicApiController;
namespace Furion.Application
{
[DynamicApiController]
public class SqlService
{
private ISqlExecuteProxy _sqlExecuteProxy;
public SqlService(ISqlExecuteProxy sqlExecuteProxy)
{
_sqlExecuteProxy = sqlExecuteProxy;
}
}
}
var persons = personRepository.SqlProcedureQuery("proc_GetPersons");
var persons = "proc_GetPersons".SqlProcedureQuery();
9.14.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.14.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.14.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.14.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.14.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.14.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.14.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.14.3 执行复杂存储过程
在存储过程中,有一种例子非常复杂,那就是既有 INPUT
参数,又有 OUTPUT
参数,还有 RETURN
参数,同时还输出 结果集 💥,如:
CREATE PROC PROC_Output
@Id INT, // 输入参数
@Name NVARCHAR(32) OUTPUT, // 输出参数,还带长度
@Age INT OUTPUT // 输出参数
AS
BEGIN
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.14.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.14.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.14.3 关于 [DbParameter]
[DbParameter]
特性是用来标注 Sql
,函数
,存储过程
参数的,可配置属性:
Direction
:设置参数方向,ParameterDirection
枚举类型,默认ParameterDirection.Input
DbType
:设置参数类型,DbType
枚举类型,无默认Size
:设置参数长度的,int
类型
其中 Direction
属性是默认构造函数参数。
9.14.4 关于 ProcedureOutputResult
ProcedureOutputResult
和 ProcedureOutputResult<TResult>
是复杂存储过程执行返回模型类,有以下属性:
OutputValues
:多个输出值,ProcedureOutputValue
类型ReturnValue
:返回值,object
类型Result
:结果集,非泛型版本是DataSet
类型,否则是 泛型类型
9.14.5 存储过程参数
所有 sql
参数都支持四种方式:
DbParameter[]
:数组 类型new {}
:匿名类型new Class{}
:强类型类型(支持复杂存储过程参数)Dictionary<string,object>
类型
9.14.6 反馈与建议
给 Furion 提 Issue。