9.17 Sql 高级代理

9.17.1 关于 Sql 代理#

Sql 代理是 Furion 框架中对 Sql 操作一个非常重要的概念,通过这种方式可以大大提高 Sql 书写效率,而且后期极易维护。

Sql 代理属于 Furion 框架中一个高级功能。

9.17.2 了解 ISqlDispatchProxy#

ISqlDispatchProxy 接口是 Furion 实现被代理接口的唯一依赖,任何公开的接口一旦集成了 ISqlDispatchProxy 接口,那么这个接口就是被托管拦截Sql 操作接口。

简单定义一个 Sql 代理接口

using Furion.DatabaseAccessor;
namespace Furion.Application
{
public interface ISql : ISqlDispatchProxy
{
}
}

一旦这个接口继承了 ISqlDispatchProxy,那么它就会动态创建接口实例,而且支持依赖注入/控制反转获取实例

9.17.3 开始领略 Sql 代理#

下面我讲通过多个例子来演示 Sql 代理的用法,为什么推荐这种方式操作 Sql

支持各种方式获取实例:

9.17.3.1 构造函数方式#

private readonly Isql _sql;
public FurService(Isql sql)
{
_sql = sql;
}

9.17.3.2 方法参数注入#

public async Task<List<PersonDto>> GetAll([FromServices] Isql, string keyword)
{
}

9.17.3.3 Db.GetSqlDispatchProxy<ISql>()#

var sql = Db.GetSqlDispatchProxy<ISql>();

9.17.4 Sql 操作#

9.17.4.1 返回 DataTable#

using Furion.DatabaseAccessor;
namespace Furion.Application
{
public interface ISql : ISqlDispatchProxy
{
// 执行sql并传入参数,基元类型
[SqlExecute("select * from person where id >@id and name like %@name%")]
DataTable GetPerson(int id, string name);
// 执行sql并传入参数,对象类型
[SqlExecute("select * from person where id >@id and name like %@name%")]
DataTable GetPerson(MyParam paras));
// 执行存储过程 sql,支持设置参数类型
[SqlExecute("exec PROP_NAME @id", CommandType = CommandType.StoredProcedure)]
DataTable GetPerson(int id));
// 支持多数据库操作
[SqlExecute("select * from person", DbContextLocator = typeof(MySqlDbContextLocator))]
DataTable GetPerson());
// 异步方式
[SqlExecute("select * from person", DbContextLocator = typeof(MySqlDbContextLocator))]
Task<DataTable> GetPersonAsync());
}
}
关于参数

Sql 代理参数查找规则:

如果方法的参数是 基元类型(或 string值类型),则自动将这些类型组合成 Dictionary<string, object> 作为 Sql 参数。命令参数可使用方法同名参数加 @ 符号。

如果方法的参数是 类类型,那么自动遍历该类公开实例属性生成 DbParameter[] 数组,每一个属性名都将是命令参数,不区分大小写,如:

public class MyModel
{
public int Id {get;set;}
public string Name {get; set;}
}

那么 sql 语句可以直接使用属性名作为参数:

select * from person where id > @id and name = @name;

9.17.4.2 返回 T 或 List<T>#

using Furion.DatabaseAccessor;
namespace Furion.Application
{
public interface ISql : ISqlDispatchProxy
{
// 执行sql并传入参数,基元类型
[SqlExecute("select * from person where id >@id and name like %@name%")]
List<Person> GetPerson(int id, string name);
// 执行sql并传入参数,对象类型
[SqlExecute("select * from person where id >@id and name like %@name%")]
List<Person> GetPerson(MyParam paras));
// 执行存储过程 sql,支持设置参数类型
[SqlExecute("exec PROP_NAME @id", CommandType = CommandType.StoredProcedure)]
Person GetPerson(int id));
// 支持多数据库操作
[SqlExecute("select * from person", DbContextLocator = typeof(MySqlDbContextLocator))]
List<Person> GetPerson());
// 异步方式
[SqlExecute("select * from person", DbContextLocator = typeof(MySqlDbContextLocator))]
Task<List<Person>> GetPersonAsync());
}
}

9.17.4.3 返回 DataSet#

using Furion.DatabaseAccessor;
namespace Furion.Application
{
public interface ISql : ISqlDispatchProxy
{
// 执行sql并传入参数,基元类型
[SqlExecute(@"
select * from person where id >@id and name like %@name%;
select top 10 * from student where Id >@id;")]
DataSet GetData(int id, string name);
// 执行sql并传入参数,对象类型
[SqlExecute(@"
select * from person where id >@id and name like %@name%;
select top 10 * from student where Id >@id;")]
DataSet GetData(MyParam paras));
// 执行存储过程 sql,支持设置参数类型
[SqlExecute(@"
exec PROP_NAME @id;
select * from person;", CommandType = CommandType.StoredProcedure)]
DataSet GetData(int id));
// 支持多数据库操作
[SqlExecute(@"
select * from person;
select * from student;", DbContextLocator = typeof(MySqlDbContextLocator))]
DataSet GetData());
// 异步方式
[SqlExecute(@"
select * from person;
select * from student;
select 1;", DbContextLocator = typeof(MySqlDbContextLocator))]
Task<DataSet> GetDataAsync());
}
}

9.17.4.4 返回 Tuple<T1,...T8>#

using Furion.DatabaseAccessor;
namespace Furion.Application
{
public interface ISql : ISqlDispatchProxy
{
// 执行sql并传入参数,基元类型
[SqlExecute(@"
select * from person where id >@id and name like %@name%;
select top 10 * from student where Id >@id;")]
(List<Person>,List<Student>) GetData(int id, string name);
// 执行sql并传入参数,对象类型
[SqlExecute(@"
select * from person where id >@id and name like %@name%;
select top 10 * from student where Id >@id;")]
(List<Person>,List<Student>) GetData(MyParam paras));
// 执行存储过程 sql,支持设置参数类型
[SqlExecute(@"
exec PROP_NAME @id;
select * from person;", CommandType = CommandType.StoredProcedure)]
(List<Person>,List<Student>) GetData(int id));
// 支持多数据库操作
[SqlExecute(@"
select * from person;
select * from student;", DbContextLocator = typeof(MySqlDbContextLocator))]
(List<Person>,List<Student>) GetData());
// 异步方式
[SqlExecute(@"
select * from person;
select * from student;
select 1;", DbContextLocator = typeof(MySqlDbContextLocator))]
Task<(List<Person>,List<Student>,int)> GetDataAsync());
}
}

9.17.4.5 返回 单行单列#

using Furion.DatabaseAccessor;
namespace Furion.Application
{
public interface ISql : ISqlDispatchProxy
{
[SqlExecute("select Name from person where id = @id")]
string GetValue(int id);
[SqlExecute("select age from person where id = @id")]
int GetValue(int id);
[SqlExecute("select Name from person where id = @id")]
Task<string> GetValueAsync(int id);
}
}

9.17.4.6 无返回值#

using Furion.DatabaseAccessor;
namespace Furion.Application
{
public interface ISql : ISqlDispatchProxy
{
[SqlExecute("insert into person(Name,Age) values(@name,@age)")]
void Insert(MyParam dto);
[SqlExecute("delete from person where id = @id")]
void Delete(int id);
[SqlExecute("update person set name=@name where id=@id")]
void Update(int id, string name);
}
}

9.17.5 存储过程 操作#

9.17.5.1 返回 DataTable#

using Furion.DatabaseAccessor;
namespace Furion.Application
{
public interface ISql : ISqlDispatchProxy
{
[SqlProcedure("PROC_Name")]
DataTable GetPersons(MyParam dto);
[SqlProcedure("PROC_Name")]
DataTable GetPersons(int id);
[SqlProcedure("PROC_Name")]
DataTable GetPersons(int id, string name);
}
}

9.17.5.2 返回 T 或 List<T>#

using Furion.DatabaseAccessor;
namespace Furion.Application
{
public interface ISql : ISqlDispatchProxy
{
[SqlProcedure("PROC_Name")]
List<Person> GetPersons(MyParam dto);
[SqlProcedure("PROC_Name")]
List<Person> GetPersons(int id);
[SqlProcedure("PROC_Name")]
Person GetPersons(int id, string name);
}
}

9.17.5.3 返回 DataSet#

using Furion.DatabaseAccessor;
namespace Furion.Application
{
public interface ISql : ISqlDispatchProxy
{
[SqlProcedure("PROC_Name")]
DataSet GetData(MyParam dto);
[SqlProcedure("PROC_Name")]
DataSet GetData(int id);
[SqlProcedure("PROC_Name")]
DataSet GetData(int id, string name);
}
}

9.17.5.4 返回 Tuple(T1,...T8)#

using Furion.DatabaseAccessor;
namespace Furion.Application
{
public interface ISql : ISqlDispatchProxy
{
[SqlProcedure("PROC_Name")]
(List<Person>, List<Student>) GetData(MyParam dto);
[SqlProcedure("PROC_Name")]
(List<Person>, List<Student>) GetData(int id);
[SqlProcedure("PROC_Name")]
(List<Person>, List<Student>, Person, int) GetData(int id, string name);
}
}

9.17.5.4 返回 单行单列#

using Furion.DatabaseAccessor;
namespace Furion.Application
{
public interface ISql : ISqlDispatchProxy
{
[SqlProcedure("PROC_Name")]
object GetValue(MyParam dto);
[SqlProcedure("PROC_Name")]
string GetValue(int id);
[SqlProcedure("PROC_Name")]
int GetValue(int id, string name);
}
}

9.17.5.6 无返回值#

using Furion.DatabaseAccessor;
namespace Furion.Application
{
public interface ISql : ISqlDispatchProxy
{
[SqlProcedure("PROC_Name")]
void GetValue(MyParam dto);
[SqlProcedure("PROC_Name")]
void GetValue(int id);
[SqlProcedure("PROC_Name")]
void GetValue(int id, string name);
}
}

9.17.5.7 带 OUTPUT/RETURN 返回#

using Furion.DatabaseAccessor;
namespace Furion.Application
{
public interface ISql : ISqlDispatchProxy
{
[SqlProcedure("PROC_Name")]
ProcedureOutputResult GetOutput(ProcOutputModel pams);
[SqlProcedure("PROC_Name")]
ProcedureOutputResult GetOutput(ProcOutputModel pams);
[SqlProcedure("PROC_Name")]
ProcedureOutputResult<(List<Person>, List<Student>)> GetOutput(ProcOutputModel pams);
}
}

9.17.5 函数 操作#

using Furion.DatabaseAccessor;
namespace Furion.Application
{
public interface ISql : ISqlDispatchProxy
{
[SqlFunction("FN_Name")] // 标量函数
string GetValue(MyParam dto);
[SqlProcedure("FN_Name")] // 表值函数
List<Person> GetPersons(int id);
}
}
补充说明

Sql 代理会自动判断返回值然后自动执行特定函数类型。

9.17.6 为什么用它?#

通过上面的例子大家就可以了解,这种方式操作 sql 非常简单,而且极易维护。大家不用去关心返回值,关心用哪个方法,所有东西会自动给你处理好。

所以,如果需要用 Sql 操作,推荐使用 Sql 高级代理。

9.17.7 反馈与建议#

与我们交流

给 Furion 提 Issue