9.17 Sql 高级代理

9.17.1 关于 Sql 代理

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

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

9.17.2 了解 ISqlDispatchProxy

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

简单定义一个 Sql 代理接口

using Fur.DatabaseAccessor;
namespace Fur.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 App.GetSqlDispatchProxy<ISql>()

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

9.17.4 Sql 操作

9.17.4.1 返回 DataTable

using Fur.DatabaseAccessor;
namespace Fur.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 Fur.DatabaseAccessor;
namespace Fur.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 Fur.DatabaseAccessor;
namespace Fur.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 Fur.DatabaseAccessor;
namespace Fur.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 Fur.DatabaseAccessor;
namespace Fur.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 Fur.DatabaseAccessor;
namespace Fur.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 Fur.DatabaseAccessor;
namespace Fur.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 Fur.DatabaseAccessor;
namespace Fur.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 Fur.DatabaseAccessor;
namespace Fur.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 Fur.DatabaseAccessor;
namespace Fur.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 Fur.DatabaseAccessor;
namespace Fur.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 Fur.DatabaseAccessor;
namespace Fur.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 Fur.DatabaseAccessor;
namespace Fur.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 Fur.DatabaseAccessor;
namespace Fur.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 反馈与建议

与我们交流

给 Fur 提 Issue