9.12、切面上下文(TangentDbContext)

切面上下文是一种全新的面向切面操作数据库方式。

什么是切面上下文

切面上下文是 Hoa Framework 框架独创的面向切面方式操作数据库方式,主要用来解决 sql 语句、存储过程、函数调用情况。

可能有些时候我们避免不了写 sql 的方式(特别注意,除非 Linq/Lambda 方式不能做到,才用切面上下文),如:

传统写法(以后不推荐)

// sql方式
_testRepository.FromSql("select name from test where id=@id"
        , new SqlParameter[]{ new SqlParameter("@id", 1) });
        
// 执行存储过程
_testRepository.SqlProcedureQuery("PROC_Name", new ProcModel(){});

// 执行函数
_testRepository.SqlFunctionQuery("Func_Name", new FuncModel(){});

上面的方式似乎没有上面问题,但是如果多个地方需要用到这些 sql 或 存储过程 或 函数调用,就会散落到处都是,不利于维护

所以,Hoa Framework 框架设计出全新的方式,主要用来解决上述代码多次调用散落问题。

如何使用(推荐)

第一步

定义一个接口(只需要接口),并继承 ITangentDependency接口,如:IFallScatteredQuery,如:

using Hoa.DbManager.Tangents;

namespace Hoa.Application
{
    // 必须继承 ITangentDependency 接口
    public interface IFallScatteredQuery: ITangentDependency
    {
        // 执行原始 sql 查询
        [Sentence("select name from dbo.test where id=@id")]
        string GetName(int id);
        
        // 执行存储过程
        [Procedure("PROC_Name")]
        IEnumerable<Test> GetProcResult(object model);
        
        // 执行函数
        [ScalarFunction("Func_Name")]
        int GetFuncReuslt(object model);
    }
}

第二步

通过依赖注入 ITangentDbContext 切面上下文接口,并调用 For<T> 进行初始化,如:

using Hoa.Application;
using Hoa.DbManager.Tangents;
using Microsoft.AspNetCore.Mvc;

namespace Hoa.Web.Host.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class HoaController : ControllerBase
    {
        // 构造函数初始化
        private readonly IFallScatteredQuery _tangent;
        public HoaController(ITangentDbContext tangentDbContext)
        {
            // 解析接口信息
            _tangent = tangentDbContext.For<IFallScatteredQuery>();
        }

        [HttpGet]
        [Route(nameof(Test))]
        public string Test()
        {
           // 执行sql
           var name = _tangent.GetName(1);    // 自动查询数据库
           
           // 执行存储过程
           var tests = _tangent.GetProcResult(new { name = "Monk" });
           
           // 执行函数
           var num = _tangent.GetFuncReuslt(new { id = 10});
           
           return "Powered by Monk";
        }
    }
}

神奇吧!通过这种方式,Hoa Framework 会自动查询数据库并转换成指定的结果。再也不怕代码难维护了!😘

特性说明

目前 切面上下文支持 三种 特性解析:

  • [Sentence(sql, DbContextIdentifier=)]:支持传入 sql 语句,支持命令参数防止 sql 注入。

  • [Procedure(name, DbContextIdentifier=)]:支持传入存储过程名称

  • [ScalarFunction(name, DbContextIdentifier=)]:支持传入函数名称

其中 DbContextIdentifier 参数是 Type 类型,也就是 数据库上下文标识类。见 9.11、多上下文、读写分离 章节

支持返回值

TangentDbContext 几乎支持所有返回值类型,如:

  • Object

  • 除了 Enum 以外的所有值类型和 string 类型,如:int, bool, decimal, string, float, long等等

  • 所有可枚举集合类型,包括 ArrayListIEnumerable

  • DataTableDataSet 类型

  • ValueTuple 元组类型

支持元组返回多个值

using Hoa.DbManager.Tangents;
using System.Collections.Generic;
using System.Data;

namespace Hoa.Application
{
    public interface IFallScatteredQuery : ITangentDependency
    {
        [Sentence(@"
            select * from dbo.brokers;
            select * from dbo.brokers where id > @id;
            select * from dbo.brokers where name = @name
        ")]
        DataSet GetDataSet(int id, string name);

        [Sentence(@"
            select top 2 * from dbo.brokers;
            select * from dbo.brokers where id > @id;
            select * from dbo.brokers where name = @name
        ")]
        (IEnumerable<Broker> brokers1, IEnumerable<Broker> brokers2, IEnumerable<Broker> brokers3) GetValueTuple(int id, string name);
    }
}
var dataset = _tangent.GetDataSet(1, "Monk2");
var (broker1, borker2, borker3) = _tangent.GetValueTuple(0, "Monk");

支持复杂类型返回并自动映射

[Procedure("PROC_Name", SourceType = typeof((A, IEnumerable<B>, IEnumerable<C>, IEnumerable<D>)))]
(ADto a, IEnumerable<BDto> b, IEnumerable<CDto> c, IEnumerable<DDto> d) PRGetPersonDemographicDetail(Parameter_PersonID parameter);
config.ForType<A, ADto>().ConvertSourceMemberUnderlineSplitNameToCamelCase();
config.ForType<(A a, IEnumerable<B> b, IEnumerable<C> a, IEnumerable<D> d), (ADto aDto, IEnumerable<BDto> bDto, IEnumerable<CDto> cDto, IEnumerable<DDto> dDto)>()
                .ConvertSourceMemberUnderlineSplitNameToCamelCase()
                .Map(dest => dest.aDto, src => src.a)
                .Map(dest => dest.aDto.B, src => src.b)
                .Map(dest => dest.aDto.C, src => src.c)
                .Map(dest => dest.aDto.D, src => src.d);

多上下文配置

切面上下文还支持多上下文操作,如:

using Hoa.Core;
using Hoa.Core.Web.Entities;
using Hoa.DbManager.Tangents;
using System.Collections.Generic;

namespace Hoa.Application
{
    public interface IFallScatteredQuery : ITangentDependency
    {
        [Procedure("PROC_Name", DbContextIdentifier = typeof(OtherDbContextIdentifier))]
        IEnumerable<Entity> GetEntities(Model parameter);
    }
}

自动映射到Dto类型

通常我们数据库返回的是我们的实体模型,这个时候,我们还需要手动的调用 .Adapt<DtoType>DtoType 类型,所以,切面上下文提供了一种更加便捷的方式,只需要指定 SouceType 即可,如:

using Hoa.Core;
using Hoa.Core.Web.Entities;
using Hoa.DbManager.Tangents;
using System.Collections.Generic;

namespace Hoa.Application
{
    public interface IFallScatteredQuery : ITangentDependency
    {
        // 设置SourceType 为执行真正的返回值,然后方法的返回值设置为Dto即可
        // 实际上内部会自动帮你将 SourceType 类型  Adapt 到 方法的返回值类型
        
        [Procedure("PROC_Name", SouceType = typeof(IEnumerable<Entity>))]
        IEnumerable<Dto> GetDtos(Model parameter);
    }
}

特别注意

不建议在切面上下文中做 增删改操作(即使框架本身支持)!!!!

最后更新于