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

9.15 Sql 操作

温馨提示

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

例子说明

本章节例子均以 sql server 数据库写的例子,命令参数统一用 @ 符号,但不同数据库的参数前缀有所不同,如:sql server 采用 @,oracle 采用 :,my sql 采用 ?

9.15.1 关于 Sql

Furion 框架提供非常多且灵活的 sql 操作方法,且性能不输于 dapper,同时逼近 ADO.NET 原生操作。

9.15.2 懒人无敌 Sql 🐮

9.15.2.1 返回 DataTable

// ==== 同步操作 ====// 示例一var dataTable = "select * from person".SqlQuery();// 示例二var dataTable = "select top 10 * from person where id > @id".SqlQuery(new {id = 10});// 示例三var dataTable = "select Id, Name, Age from person where name like @name".SqlQuery(new Dictionary<string,object>{ {"name", "%Furion%"} });// 示例四var dataTable = "select * from person where name=@name limit 1,10".SqlQuery(new []{ new MySqlParameter("name","Furion") });// 示例五var dataTable = "select * from person where id>@id and name like @name".SqlQuery(new YourModel { Id = 1, Name = "%Furion%" });// 示例六var dataTable = "exec PROC_GetPerson @id".SqlQuery(new {id = 10});// 示例七var dataTable = "select * from FN_GetPersons(@id)".SqlQuery(new {id = 10});// 示例八var dataTable = @"select * from person pleft join personDetail pd on p.Id == pd.pidwhere p.Id > @id;".SqlQuery(new {id = 10});// ==== 异步操作 ====// 示例一var dataTable = await "select * from person".SqlQueryAsync();// 示例二var dataTable = await "select top 10 * from person where id > @id".SqlQueryAsync(new {id = 10});// 示例三var dataTable = await "select Id, Name, Age from person where name like @name".SqlQueryAsync(new Dictionary<string,object>{ {"name", "%Furion%"} });// 示例四var dataTable = await "select * from person where name=@name limit 1,10".SqlQueryAsync(new []{ new MySqlParameter("name","Furion") });// 示例五var dataTable = await "select * from person where id>@id and name like @name".SqlQueryAsync(new YourModel { Id = 1, Name = "%Furion%" });// 示例六var dataTable = await "exec PROC_GetPerson @id".SqlQueryAsync(new {id = 10});// 示例七var dataTable = await "select * from FN_GetPersons(@id)".SqlQueryAsync(new {id = 10});// 示例八var dataTable = await @"select * from person pleft join personDetail pd on p.Id == pd.pidwhere p.Id > @id;".SqlQueryAsync(new {id = 10});

9.15.2.2 返回 List<T>

// ==== 同步操作 ====// 示例一var persons = "select * from person".SqlQuery<Person>();// 示例二var persons = "select top 10 * from person where id > @id".SqlQuery<Person>(new {id = 10});// 示例三var persons = "select Id, Name, Age from person where name like @name".SqlQuery<Person>(new Dictionary<string,object>{ {"name", "%Furion%"} });// 示例四var persons = "select * from person where name=@name limit 1,10".SqlQuery<Person>(new []{ new MySqlParameter("name","Furion") });// 示例五var persons = "select * from person where id>@id and name like @name".SqlQuery<Person>(new YourModel { Id = 1, Name = "%Furion%" });// 示例六var persons = "exec PROC_GetPerson @id".SqlQuery<Person>(new {id = 10});// 示例七var persons = "select * from FN_GetPersons(@id)".SqlQuery<Person>(new {id = 10});// 示例八var persons = @"select * from person pleft join personDetail pd on p.Id == pd.pidwhere p.Id > @id;".SqlQuery<Person>(new {id = 10});// ==== 异步操作 ====// 示例一var persons = await "select * from person".SqlQueryAsync<Person>();// 示例二var persons = await "select top 10 * from person where id > @id".SqlQueryAsync<Person>(new {id = 10});// 示例三var persons = await "select Id, Name, Age from person where name like @name".SqlQueryAsync<Person>(new Dictionary<string,object>{ {"name", "%Furion%"} });// 示例四var persons = await "select * from person where name=@name limit 1,10".SqlQueryAsync<Person>(new []{ new MySqlParameter("name","Furion") });// 示例五var persons = await "select * from person where id>@id and name like @name".SqlQueryAsync<Person>(new YourModel { Id = 1, Name = "%Furion%" });// 示例六var persons = await "exec PROC_GetPerson @id".SqlQueryAsync<Person>(new {id = 10});// 示例七var persons = await "select * from FN_GetPersons(@id)".SqlQueryAsync<Person>(new {id = 10});// 示例八var persons = await @"select * from person pleft join personDetail pd on p.Id == pd.pidwhere p.Id > @id;".SqlQueryAsync<Person>(new {id = 10});

9.15.2.3 返回 DataSet

// ==== 同步操作 ====// 示例一var dataSet = @"select * from person;select * from student;".SqlQueries();// 示例二var dataSet = @"select * from person where Id > @id;select * from student where Name like @name;".SqlQueries(new {id = 1, name = "%furion%"});// 示例三var dataSet = @"select * from person;exec PROC_GetStudents(@id);select 'Furion';select * from FN_GetPerson(@id);".SqlQueries(new {id = 1});// ==== 异步操作 ====// 示例一var dataSet = await @"select * from person;select * from student;".SqlQueriesAsync();// 示例二var dataSet = await @"select * from person where Id > @id;select * from student where Name like @name;".SqlQueriesAsync(new {id = 1, name = "%furion%"});// 示例三var dataSet = await @"select * from person;exec PROC_GetStudents(@id);select 'Furion';select * from FN_GetPerson(@id);".SqlQueriesAsync(new {id = 1});

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

// ==== 同步操作 ====// 示例一var (persons, students) = @"select * from person;select * from student;".SqlQueries<Person,Student>();// 示例二var (persons, students) = @"select * from person where Id > @id;select * from student where Name like @name;".SqlQueries<Person,Student>(new {id = 1, name = "%furion%"});// 示例三var (persons, students, string, PersonDto) = @"select * from person;exec PROC_GetStudents(@id);select 'Furion';select * from FN_GetPerson(@id);".SqlQueries<Person, Student, string, PersonDto>(new {id = 1});// ==== 异步操作 ====// 示例一var (persons, students) = await @"select * from person;select * from student;".SqlQueriesAsync<Person,Student>();// 示例二var (persons, students) = await @"select * from person where Id > @id;select * from student where Name like @name;".SqlQueriesAsync<Person,Student>(new {id = 1, name = "%furion%"});// 示例三var (persons, students, string, PersonDto) = await @"select * from person;exec PROC_GetStudents(@id);select 'Furion';select * from FN_GetPerson(@id);".SqlQueriesAsync<Person, Student, string, PersonDto>(new {id = 1});

9.15.2.5 返回 单行单列

// ==== 同步操作 ====// 示例一var value = "select Name from person where id = @id".SqlScalar(new {id = 1});// 示例二var value = "select Name from person where id = @id".SqlScalar<string>(new {id = 1});// 示例三var value = "select Age from person where id = @id".SqlScalar<int>(new {id = 1});// ==== 异步操作 ====// 示例一var value = await "select Name from person where id = @id".SqlScalarAsync(new {id = 1});// 示例二var value = await "select Name from person where id = @id".SqlScalarAsync<string>(new {id = 1});// 示例三var value = await "select Age from person where id = @id".SqlScalarAsync<int>(new {id = 1});

9.15.2.6 返回 受影响行数

// ==== 同步操作 ====// 示例一var rowEffects = "insert into person(Name,Age,Address) values(@name,@age,@address)".SqlNonQuery(person);// 示例二var rowEffects = @"insert into person(Name,Age,Address) values(@name,@age,@address);insert into person(Name,Age,Address) values(@name,@age,@address);".SqlNonQuery(persons);// 示例三var rowEffects = "update person set name=@name where id=@id".SqlNonQuery(new {id=1, name="百小僧"});// 示例四var rowEffects = "delete from person where @id > 10".SqlNonQuery(new {id=1});// ==== 异步操作 ====// 示例一var rowEffects = await "insert into person(Name,Age,Address) values(@name,@age,@address)".SqlNonQueryAsync(person);// 示例二var rowEffects = @"insert into person(Name,Age,Address) values(@name,@age,@address);insert into person(Name,Age,Address) values(@name,@age,@address);".SqlNonQueryAsync(persons);// 示例三var rowEffects = await "update person set name=@name where id=@id".SqlNonQueryAsync(new {id=1, name="百小僧"});// 示例四var rowEffects = await "delete from person where @id > 10".SqlNonQueryAsync(new {id=1});

9.15.3 懒人无敌 存储过程 🐮

9.15.3.1 返回 DataTable

// ==== 同步操作 ====// 示例一var dataTable = "PROC_Name".SqlProcedureQuery();// 示例二var dataTable = "PROC_Name".SqlProcedureQuery(new {id = 1});// 示例三var dataTable = "PROC_Name".SqlProcedureQuery(new {id = 1, age = 27});// ==== 异步操作 ====// 示例一var dataTable = await "PROC_Name".SqlProcedureQueryAsync();// 示例二var dataTable = await "PROC_Name".SqlProcedureQueryAsync(new {id = 1});// 示例三var dataTable = await "PROC_Name".SqlProcedureQueryAsync(new {id = 1, age = 27});

9.15.3.2 返回 List<T>

// ==== 同步操作 ====// 示例一var persons = "PROC_Name".SqlProcedureQuery<Person>();// 示例二var persons = "PROC_Name".SqlProcedureQuery<Person>(new {id = 1});// 示例三var persons = "PROC_Name".SqlProcedureQuery<Person>(new {id = 1, age = 27});// ==== 异步操作 ====// 示例一var persons = await "PROC_Name".SqlProcedureQueryAsync<Person>();// 示例二var persons = await "PROC_Name".SqlProcedureQueryAsync<Person>(new {id = 1});// 示例三var persons = await "PROC_Name".SqlProcedureQueryAsync<Person>(new {id = 1, age = 27});

9.15.3.3 返回 DataSet

// ==== 同步操作 ====// 示例一var dataSet = "PROC_Name".SqlProcedureQueries();// 示例二var dataSet = "PROC_Name".SqlProcedureQueries(new {id = 1});// 示例三var dataSet = "PROC_Name".SqlProcedureQueries(new {id = 1, age = 27});// ==== 异步操作 ====// 示例一var dataSet = await "PROC_Name".SqlProcedureQueriesAsync();// 示例二var dataSet = await "PROC_Name".SqlProcedureQueriesAsync(new {id = 1});// 示例三var dataSet = await "PROC_Name".SqlProcedureQueriesAsync(new {id = 1, age = 27});

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

// ==== 同步操作 ====// 示例一var persons = "PROC_Name".SqlProcedureQueries<Person>();// 示例二var (persons,students) = "PROC_Name".SqlProcedureQueries<Person,Student>(new {id = 1});// 示例三var (persons,students,string) = "PROC_Name".SqlProcedureQueries<Person,Student,string>(new {id = 1, age = 27});// 示例四var (persons,students,personDetail,string) = "PROC_Name".SqlProcedureQueries<Person,Student,PersonDetail,string>(new {id = 1, age = 27});// ==== 异步操作 ====// 示例一var persons = await "PROC_Name".SqlProcedureQueriesAsync<Person>();// 示例二var (persons,students) = await "PROC_Name".SqlProcedureQueriesAsync<Person,Student>(new {id = 1});// 示例三var (persons,students,string) = await "PROC_Name".SqlProcedureQueriesAsync<Person,Student,string>(new {id = 1, age = 27});// 示例四var (persons,students,personDetail,string) = await "PROC_Name".SqlProcedureQueriesAsync<Person,Student,PersonDetail,string>(new {id = 1, age = 27});

9.15.3.5 返回 单行单列

// ==== 同步操作 ====// 示例一var value = "PROC_Name".SqlProcedureScalar(new {id = 1});// 示例二var value = "PROC_Name".SqlProcedureScalar<string>(new {id = 1, name = "新生帝", address ="广东省中山市"});// 示例三var value = "PROC_Name".SqlProcedureScalar<int>(new {id = 1,  address ="广东省中山市"});// ==== 异步操作 ====// 示例一var value = await "PROC_Name".SqlProcedureScalarAsync(new {id = 1});// 示例二var value = await "PROC_Name".SqlProcedureScalarAsync<string>(new {id = 1, name = "新生帝", address ="广东省中山市"});// 示例三var value = await "PROC_Name".SqlProcedureScalarAsync<int>(new {id = 1,  address ="广东省中山市"});

9.15.3.6 返回 受影响行数

// ==== 同步操作 ====// 示例一var rowEffects = "PROC_Name".SqlProcedureNonQuery(person);// 示例二var rowEffects = "PROC_Name".SqlProcedureNonQuery(new {id = 1, name = "新生帝", address ="广东省中山市"});// 示例三var rowEffects = "PROC_Name".SqlProcedureNonQuery(new {id=1, name="百小僧"});// 示例四var rowEffects = "PROC_Name".SqlProcedureNonQuery(new {id=1});// ==== 异步操作 ====// 示例一var rowEffects = await "PROC_Name".SqlProcedureNonQueryAsync(person);// 示例二var rowEffects = await "PROC_Name".SqlProcedureNonQueryAsync(new {id = 1, name = "新生帝", address ="广东省中山市"});// 示例三var rowEffects = await "PROC_Name".SqlProcedureNonQueryAsync(new {id=1, name="百小僧"});// 示例四var rowEffects = await "PROC_Name".SqlProcedureNonQueryAsync(new {id=1});

9.15.3.7 带 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;
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; }    // 返回值    }}
// ==== 同步操作 ====// 示例一ProcedureOutputResult result = "PROC_Name".SqlProcedureOutput(new ProcOutputModel{ Id=1});// 示例二ProcedureOutputResult result = "PROC_Name".SqlProcedureOutput(new ProcOutputModel{ Id=1});// 示例三ProcedureOutputResult<(List<Person>, List<Student>)> result = "PROC_Name".SqlProcedureOutput<(List<Person>, List<Student>)>(new ProcOutputModel{ Id=1});// ==== 异步操作 ====// 示例一ProcedureOutputResult result = await "PROC_Name".SqlProcedureOutputAsync(new ProcOutputModel{ Id=1});// 示例二ProcedureOutputResult result = await "PROC_Name".SqlProcedureOutputAsync(new ProcOutputModel{ Id=1});// 示例三ProcedureOutputResult<(List<Person>, List<Student>)> result = await "PROC_Name".SqlProcedureOutputAsync<(List<Person>, List<Student>)>(new ProcOutputModel{ Id=1});

9.15.4 懒人无敌 函数 🐮

9.15.4.1 标量函数

// ==== 同步操作 ====// 示例一var value = "FN_Name".SqlFunctionScalar();// 示例二var value = "FN_Name".SqlFunctionScalar(new {id = 1});// 示例三var value = "FN_Name".SqlFunctionScalar<string>();// 示例四var value = "FN_Name".SqlFunctionScalar<int>(new {id = 1});// ==== 异步操作 ====// 示例一var value = await "FN_Name".SqlFunctionScalarAsync();// 示例二var value = await "FN_Name".SqlFunctionScalarAsync(new {id = 1});// 示例三var value = await "FN_Name".SqlFunctionScalarAsync<string>();// 示例四var value = await "FN_Name".SqlFunctionScalarAsync<int>(new {id = 1});

9.15.4.2 表值函数

// ==== 同步操作 ====// 示例一var dataTable = "FN_Name".SqlFunctionQuery();// 示例二var dataTable = "FN_Name".SqlFunctionQuery(new {id = 1});// 示例三var persons = "FN_Name".SqlFunctionQuery<Person>();// 示例四var persons = "FN_Name".SqlFunctionQuery<Person>(new {id = 1});// ==== 异步操作 ====// 示例一var dataTable = await "FN_Name".SqlFunctionQueryAsync();// 示例二var dataTable = await "FN_Name".SqlFunctionQueryAsync(new {id = 1});// 示例三var persons = await "FN_Name".SqlFunctionQueryAsync<Person>();// 示例四var persons = await "FN_Name".SqlFunctionQueryAsync<Person>(new {id = 1});

9.15.5 设置超时时间

var data = "select * from table".SetCommandTimeout(100).SqlQuery(); // 单位秒

9.15.6 ISqlRepository 操作

ISqlRepository 仓储是专门处理 Sql 操作的,无需实体方式,所有接口和 懒人无敌 方式一样:

// 示例一var dataTable = sqlRepository.SqlQuery("select * from person");// 示例二var dataTable = sqlRepository.SqlQuery("select * from person where id > @id", new { id = 10});// 示例四var persons = sqlRepository.SqlQuery<Person>("select * from person");// 示例五var persons = sqlRepository.SqlQuery<Person>("select * from person where id > @id", new { id = 10});// 不再举例子。。。
补充说明

不管是哪种方式操作 Sql ,方法名参数都是一致的,如:

  • SqlQuery
  • SqlQueryAsync
  • SqlQueries
  • SqlQueriesAsync
  • SqlNonQuery
  • SqlNonQueryAsync
  • SqlScalar
  • SqlScalarAsync
  • SqlProcedureQuery
  • SqlProcedureQueryAsync
  • SqlProcedureQueries
  • SqlProcedureQueriesAsync
  • SqlProcedureScalar
  • SqlProcedureScalarAsync
  • SqlProcedureNonQuery
  • SqlProcedureNonQueryAsync
  • SqlProcedureOutput
  • SqlProcedureOutputAsync
  • SqlFunctionScalar
  • SqlFunctionScalarAsync
  • SqlFunctionQuery
  • SqlFunctionQuery

9.15.7 IRepository 操作

IRepository 也能操作 sql,调用方法也是和上面一致的,如:

var dataTable = repository.Sql().SqlQuery("select * from person");
特别说明

由于篇幅有限,不再列举所有例子。

9.15.8 IRepository<TEntity> 操作

IRepository<TEntity> 也能操作 sql,调用方法也是和上面一致的,如:

var dataTable = personRepository.SqlQuery("select * from person");
特别说明

由于篇幅有限,不再列举所有例子。

9.15.9 关于 Sql 参数

所有 sql存储过程函数 参数都支持四种方式:

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

建议除了复杂的存储过程(带 OUTPUT/RETURN)的以外,所有参数建议使用 new {} 匿名类型,如果需要动态参数,则可以使用 Dictionary<string,object> 类型。

参数大小写问题

由于不同数据库对查询参数大小写问题处理不一致,所以建议所有查询参数和参数名或属性名完全一致

9.15.10 多数据库 Sql 操作 💯 💛

Furion 框架拥有非常灵活的多数据库操作方式,只需通过多数据库上下文定位器即可动态切换数据库。

9.15.10.1 懒人无敌 🐮 方式

var dataTable = "select * from person".Change<MySqlDbContextLocator>().SqlQuery();var persons = "select * from person whre id > @id".Change<SqliteDbContextLocator>().SqlQuery<Person>();
补充说明

懒人方式 只需要通过 Change<TDbContextLocator> 方式即可动态切换数据库。

9.15.10.2 ISqlRepository 方式

只需要通过 ISqlRepository<TDbContextLocator> 注入或通过 sqlRepository.Change<TDbContextLocator>() 切换。

9.15.10.3 IRepository 方式

只需要通过 repository.Change<TDbContextLocator>() 获取即可。

9.15.10.4 IRepository<TEntity> 方式

只需要通过 IRepository<TEntity, TDbContextLocator> 注入或通过 personRepository.Change<TEntity, TDbContextLocator>() 切换。

9.15.11 切换数据库

Furion 框架中,不管是懒人模式还是仓储模式都是通过 .Change<TDbContextLocator> 方式切换数据库,如:

// 懒人模式var data = "select * from table".Change<MySqlDbContextLocator>().SqlQuery<Data>();// 仓储方式var data = req.Change<MySqlDbContextLocator>().SqlQuery<Data>("select * from table");

9.15.12 多线程共享作用域

默认情况下,所有的 字符串实体 拓展都有自己独立维护的 ServiceProvider 作用域。

Web 请求中,默认是 HttpContext.RequestServices,但在 非 Web,如多线程操作,后台任务,事件总线等场景下会自动创建新的作用域,实际上这是非常不必要的内存开销。

这时,我们只需要通过 .SetXXXScoped(service) 共享当前服务提供器作用域即可,如:

Scoped.Create((fac, scope) => {    "select * from table".SetContextScoped(scope.ServiceProvider).SqlQuery();});

9.15.13 静态 Default 方式构建

SqlExecutePart.Default.SetSqlString("select * from person").SqlQuery();

9.15.14 反馈与建议

与我们交流

给 Furion 提 Issue

演练场