C# 根据数据库表动态配置接口

背景

由于项目中,很多时候只需要执行SQL或者是存储过程,这个时候不想去动服务接口的代码,所以当前设计思路应运而生。

数据库表设计

1. CommonApiMainConfig

  **当前为配置主表**
字段类型是否为空说明
Idbigint主键
[Key]varchar(50)接口的主要关键键
Versionint接口的版本
RequestTypevarchar(50)请求类型 Get/Post
Remarkvarchar(500)
ProcedureNamevarchar(500)存储过程名称
Sqlvarchar(max)SQL语句 ,如果填了存储过程则忽略SQL语句
IsEnablebit是否启用
IsSystembit是否为系统
ResultTypevarchar(50)返回的数据类型(Array:多个数据表的所有数据;SingleArray:第一个数据表的所有数据;Object:第一个数据表的第一行数据)
InUservarchar(500)新增用户
Indatedatetime新增时间

2. CommonApiInputParamConfig

  **当前为输入参数配置表**
字段类型是否为空说明
Idbigint主键
[Key]varchar(50)接口的主要关键键
Versionint版本
ParameterNamevarchar(100)参数名称
ParameterTypevarchar(50)参数值类型
IsEnablebit是否启用
InUservarchar(500)新增用户
Indatedatetime新增时间

代码实现

模型

  /// <summary> 
    ///  作者:Sky
    ///  时间:2023-04-23 10:30:15  
    ///  描述:
    ///  说明:本文件由工具自动生成。
    /// </summary>
    public partial class CommonApiMainConfig
    {

        /// <summary>
        /// 请求类型 Get/Post
        /// </summary>
        public string RequestType { get; set; }

        /// <summary>
        /// 存储过程名称
        /// </summary>
        public string ProcedureName { get; set; }

        /// <summary>
        /// SQL语句 ,如果填了存储过程则忽略SQL语句
        /// </summary>
        public string Sql { get; set; }

        /// <summary>
        /// 是否为系统内置接口
        /// </summary>
        public bool? IsSystem { get; set; }

        /// <summary>
        /// 返回的数据类型(Array:多个数据表的所有数据;SingleArray:第一个数据表的所有数据;Object:第一个数据表的第一行数据)
        /// </summary>
        public string ResultType { get; set; }
        public DateTime Indate { get; set; }
        public string InUser { get; set; }
        public int Version { get; set; }
        public string Key { get; set; }
        public string Remark { get; set; }
        public bool IsEnable { get; set; }
        public long Id { get; set; }


    }


    /// <summary> 
    ///  作者:Sky
    ///  时间:2023-04-01 14:34:51  
    ///  描述:
    ///  说明:本文件由工具自动生成。
    /// </summary>
    public partial class CommonApiInputParamConfig
    {
        public long Id { get; set; }

        /// <summary>
        /// 参数名称
        /// </summary>
        public string ParameterName { get; set; }

        /// <summary>
        /// 参数值类型
        /// </summary>
        public string ParameterType { get; set; }

        /// <summary>
        /// 是否启用
        /// </summary>
        public bool IsEnable { get; set; }
        public int Version { get; set; }
        public string InUser { get; set; }
        public DateTime Indate { get; set; }
        public string Key { get; set; }


    }
  /// <summary>
    /// 返回父类
    /// </summary>
    public class ReturnBase
    {
        public ReturnBase()
        {

        }
        public ReturnBase(ResultType ResultType)
        {
            this.state = ResultType.ToString();
        }
        public ReturnBase(string message)
        {
            this.message = message;
        }
        public ReturnBase(ResultType ResultType, string message)
        {
            this.state = ResultType.ToString();
            this.message = message;
        }
        public ReturnBase(ResultType ResultType, string message, dynamic data)
        {
            this.state = ResultType.ToString();
            this.message = message;
            this.data = data;
        }
        public string state { get; set; } = ResultType.success.ToString();
        public string message { get; set; } = "操作成功!";
        /// <summary>
        /// 返回数据
        /// </summary>
        public dynamic data { get; set; }
    }

辅助代码

 
        public static string ToJson(this DataSet ds)
        {
            return Dataset2Json(ds);
        }

        public static string ToJson(this DataTable dt, bool isAppendTotal, bool isSingle)
        {
            return DataTable2Json(dt, isAppendTotal, isSingle);
        }

        public static string Dataset2Json(DataSet ds)
        {
            //total表示DataSet里dataTable的数据总条数
            StringBuilder json = new StringBuilder();
            if (ds.Tables.Count > 1)
            {
                json.Append("[");
            }
            foreach (DataTable dt in ds.Tables)
            {
                //{"total":5,"rows":[   
                //json.Append("{\"total\":");
                //if (total == -1)
                //{
                //    json.Append(dt.Rows.Count);
                //}
                //else
                //{
                //    json.Append(total);
                //}
                //json.Append(",\"data\":[");
                json.Append(DataTable2Json(dt, true));
                //json.Append(","attr1":"Large"")
                //json.Append("]},");
                json.Append(",");
            }
            if (ds.Tables.Count > 0)
            {
                json.Remove(json.Length - 1, 1);
            }
            if (ds.Tables.Count > 1)
            {
                json.Append("]");
            }
            return json.ToString();
        }
        /// <summary>
        /// 表格转JSON
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="isAppendTotal">是否添加total</param>
        /// <param name="isSingle">是否为单个</param>
        /// <returns></returns>
        public static string DataTable2Json(DataTable dt, bool isAppendTotal = false, bool isSingle = false)
        {
            StringBuilder jsonBuilder = new StringBuilder();
            if (isSingle)
            {
                jsonBuilder.Append("{");
                for (int j = 0; j < dt.Columns.Count; j++)
                {
                    jsonBuilder.Append("\"");
                    jsonBuilder.Append(dt.Columns[j].ColumnName);
                    jsonBuilder.Append("\":");
                    jsonBuilder.Append(GetRowValue(dt.Rows[0][j]));
                    jsonBuilder.Append(",");
                }
                if (dt.Columns.Count > 0)
                {
                    jsonBuilder.Remove(jsonBuilder.Length - 1, 1);
                }
                jsonBuilder.Append("}");
            }
            else
            {
                if (isAppendTotal)
                {
                    jsonBuilder.Append("{\"total\":");
                    jsonBuilder.Append($"{dt.Rows.Count},\"rows\":[");
                }
                else
                {
                    jsonBuilder.Append("[");
                }
                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    //jsonBuilder.Append("{"total":5,"rows":[");
                    jsonBuilder.Append("{");
                    for (int j = 0; j < dt.Columns.Count; j++)
                    {
                        jsonBuilder.Append("\"");
                        jsonBuilder.Append(dt.Columns[j].ColumnName);
                        jsonBuilder.Append("\":");
                        jsonBuilder.Append(GetRowValue(dt.Rows[i][j]));
                        jsonBuilder.Append(",");
                    }
                    jsonBuilder.Append("},");
                }
                if (dt.Rows.Count > 0)
                {
                    jsonBuilder.Remove(jsonBuilder.Length - 1, 1);
                }
                if (isAppendTotal)
                {
                    jsonBuilder.Append("]}");
                }
                else
                {
                    jsonBuilder.Append("]");
                }
            }
            return jsonBuilder.ToString();
        }

        private static string GetRowValue(object value)
        {
            if (value == null)
            {
                return "null";
            }
            if (value.GetType().Name == typeof(bool).Name)
            {
                return value.ToString().ToLower();
            }
            List<string> typeNames = new List<string>() { typeof(int).Name, typeof(double).Name, typeof(decimal).Name, typeof(float).Name };
            if (typeNames.IndexOf(value.GetType().Name) > -1)
            {
                return value.ToString();
            }
            return "\"" + value.ToString() + "\"";
        }

核心代码

当前代码是基于Dapper操作数据的,如有需要则将操作数据部分换成其他的;可以在这基础上继续进行改进,目前是相对比较基础的实现。

  [HttpGet]
        [HttpPost]
        [Route("api/CommonApi/{key}")]
        public dynamic CommonApi(string key, int version = 0)
        {
            try
            {
                using (var context = DapperHelper.GetContext(Factory.Eds42EMS))
                {
                    CommonApiMainConfig commonApiConfig;
                    if (version == 0) //返回最新版本有效的
                    {
                        commonApiConfig = context.Select<CommonApiMainConfig>().Where(w => w.Key == key && w.IsEnable && w.RequestType == Request.Method.Method).OrderByDescending(o => o.Version).QuerySingle();
                    }
                    else
                    {
                        commonApiConfig = context.Select<CommonApiMainConfig>().Where(w => w.Key == key && w.IsEnable && w.RequestType == Request.Method.Method && w.Version == version).QuerySingle();
                    }
                    if (commonApiConfig == null)
                    {
                        return new ReturnBase(ResultType.error, "当前接口未实现,请联系系统管理员!", null);
                    }

                    var apiParam = new Dictionary<string, dynamic>();
                    if (commonApiConfig.RequestType.ToLower() == "get")
                    {
                        var getRequestParams = Request.GetQueryNameValuePairs();
                        foreach (var item in getRequestParams)
                        {
                            apiParam.Add(item.Key, item.Value);
                        }
                    }
                    else if (commonApiConfig.RequestType.ToLower() == "post")
                    {
                        //目前仅支持常规类型的参数
                        var content = Request.Content.ReadAsStringAsync().Result;
                        if (!string.IsNullOrEmpty(content))
                        {
                            var obj = Newtonsoft.Json.Linq.JValue.Parse(content);
                            foreach (var item in obj)
                            {
                                apiParam.Add(((Newtonsoft.Json.Linq.JProperty)item).Name, ((Newtonsoft.Json.Linq.JProperty)item).Value.HasValues ? ((Newtonsoft.Json.Linq.JProperty)item).Value.ToList() : ((Newtonsoft.Json.Linq.JValue)((Newtonsoft.Json.Linq.JProperty)item).Value).Value);
                            }
                        }

                        //var fileOperateKey = obj["FileOperateKey"].ToString();
                    }
                    else
                    {
                        return new ReturnBase(ResultType.error, $"当前接口的此类型【{Request.Method.Method}】未实现,请联系系统管理员!", null);
                    }

                    var commonApiParamConfig = context.Select<CommonApiInputParamConfig>().Where(w => w.Key == key && w.Version == commonApiConfig.Version && w.IsEnable).QueryMany().ToList();
                    //DapperLambda.Dapper.DynamicParameters param = new DapperLambda.Dapper.DynamicParameters();
                    var param = new List<SqlParameter>();
                    foreach (var item in commonApiParamConfig)
                    {
                        if (apiParam.Any(a => a.Key.ToLower() == item.ParameterName.ToLower()))
                        {
                            param.Add(new SqlParameter("@" + item.ParameterName, apiParam.FirstOrDefault(a => a.Key.ToLower() == item.ParameterName.ToLower()).Value));
                        }
                        //param.Add(item.ParameterName, item.Value);
                    }
                    DataSet resultDs = new DataSet();
                    if ((string.IsNullOrEmpty(commonApiConfig.ProcedureName)) && (string.IsNullOrEmpty(commonApiConfig.Sql)))
                    {
                        return new ReturnBase(ResultType.error, $"当前接口的配置无效,必须配置ProcedureName或Sql,请联系系统管理员!", null);
                    }
                    else if (!string.IsNullOrEmpty(commonApiConfig.ProcedureName))
                    {
                        resultDs = DapperHelper.ExecuteStoredProcedure(commonApiConfig.ProcedureName, param.ToArray(), Factory.Eds42EMS);
                    }
                    else if (!string.IsNullOrEmpty(commonApiConfig.Sql))
                    {

                        resultDs = DapperHelper.ExecuteSql(commonApiConfig.Sql, param.ToArray(), Factory.Eds42EMS);
                    }

                    var resultJSON = "";
                    #region 解析返回值
                    if (!string.IsNullOrEmpty(commonApiConfig.ResultType))
                    {
                        if (commonApiConfig.ResultType.ToLower() == "array")
                        {
                            resultJSON = resultDs.ToJson();
                        }
                        else if (commonApiConfig.ResultType.ToLower() == "singlearray")
                        {
                            resultJSON = resultDs.Tables[0].ToJson(true, false);
                        }
                        else if (commonApiConfig.ResultType.ToLower() == "object")
                        {
                            resultJSON = resultDs.Tables[0].ToJson(false, true);
                        }
                        else
                        {
                            //未实现
                            return new ReturnBase(ResultType.error, $"当前接口的配置无效,必须配置正确的ResultType,请联系系统管理员!", null);
                        }
                    }
                    else
                    {
                        return new ReturnBase(ResultType.error, $"当前接口的配置无效,必须配置ResultType,请联系系统管理员!", null);
                    }
                    #endregion

                    return new ReturnBase(ResultType.success, null, Newtonsoft.Json.JsonConvert.DeserializeObject(resultJSON));
                }
            }
            catch (System.Data.SqlClient.SqlException ex)
            {
                return new ReturnBase(ResultType.error, ex.Message.ToString(), null);
            }
            catch (Exception ex)
            {
                return new ReturnBase(ResultType.error, ex.ToString(), null);
            }
        }

demo数据

CommonApiMainConfig 表数据
在这里插入图片描述
CommonApiInputParamConfig 表数据
在这里插入图片描述
存储过程Test

 -- =============================================
-- Author:		
-- Create date: 2023-4-1 16:32:08
-- Description:	测试
-- =============================================
ALTER PROCEDURE [dbo].[Test]
@a varchar(50),
@b varchar(50)
AS
BEGIN
	 select @a as a, @b as b;
	 select @a as a, @b as b;
END

示例效果

post请求跟get请求差不多,这里就不举例了。以下举例为get请求的。

  1. get请求,Key为Test的接口,地址栏传参a,b
    (由于没有带有版本号,则取的是版本最高的,也就是数据version为99的数据配置,返回的data为一个对象)
    在这里插入图片描述
  2. get请求,Key为Test的接口,地址栏传参a,b ,带有version版本则取对应版本的数据
    返回的data是一个数组,且数组中的存储过程返回了多个表
    在这里插入图片描述
    返回的data是一个数组,且只返回表格中的第一个表格
    在这里插入图片描述

后续可自行实现

  1. 输入参数的数据类型卡控
  2. 目前是只实现单值(int,string,double等)的,后续可以根据考虑一下object对象,Object对象集合等等类型作为post请求的(例如: 批量插入数据的时候就可以使用[{a:1,b:2},{a:2,b:3}])

    等等等等,思路决定出路~
阅读终点,创作起航,您可以撰写心得或摘录文章要点写篇博文。去创作
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
C# 中,可以使用 Quartz.NET 来实现定时任务,同时支持数据库持久化。Quartz.NET 是一个功能强大且灵活的开源作业调度库,可以用于创建定时任务和计划任务,支持数据库持久化和集群部署等高级功能。 要使用 Quartz.NET 实现数据库持久化,需要先创建一个用于存储调度程序数据的数据库,可以使用 Quartz.NET 提供的 SQL 脚本来创建。然后在应用程序中配置 Quartz.NET,指定数据库类型和连接字符串等信息。示例如下: ```csharp using Quartz; using Quartz.Impl; using Quartz.Impl.AdoJobStore; using Quartz.Spi; using System; using System.Collections.Specialized; class Program { static void Main() { Console.WriteLine("Starting scheduler..."); // 创建一个调度程序实例 ISchedulerFactory schedulerFactory = new StdSchedulerFactory(GetSchedulerProperties()); IScheduler scheduler = schedulerFactory.GetScheduler().Result; // 启动调度程序 scheduler.Start(); Console.WriteLine("Scheduler started."); // 创建一个作业实例 IJobDetail job = JobBuilder.Create<HelloJob>() .WithIdentity("job1", "group1") .Build(); // 创建一个触发器实例,每秒钟触发一次 ITrigger trigger = TriggerBuilder.Create() .WithIdentity("trigger1", "group1") .StartNow() .WithSimpleSchedule(x => x .WithIntervalInSeconds(1) .RepeatForever()) .Build(); // 将作业和触发器添加到调度程序中 scheduler.ScheduleJob(job, trigger); // 等待用户按下 Enter 键退出 Console.ReadLine(); // 关闭调度程序 scheduler.Shutdown(); Console.WriteLine("Scheduler stopped."); } static NameValueCollection GetSchedulerProperties() { // 配置调度程序属性,指定数据库持久化和相关参数 NameValueCollection properties = new NameValueCollection(); properties["quartz.scheduler.instanceName"] = "MyScheduler"; properties["quartz.scheduler.instanceId"] = "AUTO"; properties["quartz.jobStore.type"] = "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz"; properties["quartz.jobStore.driverDelegateType"] = "Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz"; properties["quartz.jobStore.dataSource"] = "default"; properties["quartz.dataSource.default.provider"] = "SqlServer-20"; properties["quartz.dataSource.default.connectionString"] = "Server=(local);Database=Quartz;Trusted_Connection=True;"; return properties; } } public class HelloJob : IJob { public void Execute(IJobExecutionContext context) { Console.WriteLine("Hello, Quartz.NET!"); } } ``` 这个示例会创建一个调度程序实例,然后创建一个作业实例和触发器实例,并将它们添加到调度程序中。作业类 HelloJob 实现了 IJob 接口,用于定义作业执行的逻辑。在 GetSchedulerProperties 方法中,配置了调度程序属性,指定了数据库类型和连接字符串等信息。在这个示例中,使用的是 SQL Server 数据库。 需要注意的是,在使用 Quartz.NET 进行数据库持久化时,需要保证数据库连接可靠和高效,同时需要考虑并发执行的问题。可以适当地调整作业和触发器的参数,以达到最优的性能和可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天空丶蒋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值