该篇是 Grissom.CMS 框架系列文章的第三篇, 主要介绍框架用到的核心库 EasyJsonToSql, 把标准的配置文件和数据结构解析成可执行的 sql。
该框架能实现自动化增删改查得益于 EasyJsonToSql 类库的功能:解析配置好的表结构和要进行数据库操做的数据,生成 sql,减小普通的增删改查代码量,简化“数据库 - 后端- 前端”之间的交互。html
【开源.NET】 轻量级内容管理框架Grissom.CMS(第一篇分享一个先后端分离框架)
【开源.NET】 轻量级内容管理框架Grissom.CMS(第二篇先后端交互数据结构分析)
【开源.NET】 轻量级内容管理框架Grissom.CMS(第三篇解析配置文件和数据以转换成 sql)前端
Nuget 命令git
Install-Package EasyJsonToSql
或Nuget 界面搜索: EasyJsonToSql
或下载源码(看文章底部)github
1) 假设有一张表sql
CREATE TABLE `BasUser` ( `Id` bigint(20) NOT NULL AUTO_INCREMENT, `Name` varchar(64) DEFAULT NULL, PRIMARY KEY (`Id`) );
2) 后台配置 sqlconfig数据库
const string sqlJson = @" { ""Select"":""user.*"", ""From"":""BasUser user"", ""Where"":{ ""Fields"":[ {""Name"":""Name"",""Cp"":""like""} ] }, ""OrderBy"":{""Default"":""Id""}, ""ID"":""Id"", ""Table"":""BasUser"", ""Insert"":{ ""Fields"":[ {""Name"":""Name"",""IsIgnore"":""false""} ] } } ";
3) 查询 reqeust url: http://localhost:9819/api/user/get?name=test
json
public dynamic Get(string name) { var dt = new DataTable(); // 用 json 的配置 var sqlconfig = JsonConvert.DeserializeObject<SqlConfig>(sqlJson); var sqlSb = new StringBuilder(); var nameValues = new NameValueCollection(); nameValues.Add("name", name); var builder = new Proxy().ToSelectBuilder(sqlconfig, nameValues); var builderData = builder.Data; sqlSb.AppendFormat("Select {0} From {1} Where {2}", builderData.Select, builderData.From, builderData.Where); using (var da = new MySqlDataAdapter(sqlSb.ToString(), cnnStr)) { da.Fill(dt); } return dt; }
返回结果: [{"Id":1,"Name":"test4"},{"Id":2,"Name":"test1"},{"Id":3,"Name":"test1"},{"Id":4,"Name":"test7"}]
后端
4) 新增 post url: http://localhost:9819/api/user/post
, form data: {"master":{"inserted":[{"data":{"Name":"test1"}}]}}
api
public dynamic Post() { var json = ""; using (StreamReader sr = new StreamReader(HttpContext.Current.Request.InputStream)) { json = sr.ReadToEnd(); } var jobj = JObject.Parse(json); // json 的配置 var sqlconfig = JsonConvert.DeserializeObject<SqlConfig>(sqlJson); var builder = new Proxy().ToDbBuilders(sqlconfig, jobj); var insertSqlSb = new StringBuilder(); //获取第一个sqlconfig var data = builder[0].Data; insertSqlSb.AppendFormat("insert into {0}(", data.TableName); var valueSqlSb = new StringBuilder(); var paras = new List<MySqlParameter>(); foreach (var dbField in data.Fields) { // 不是自增的字段才添加 if (!dbField.IsId) { insertSqlSb.AppendFormat("{0}", dbField.DbName); valueSqlSb.AppendFormat("@{0}", dbField.DbName); paras.Add(new MySqlParameter("@" + dbField.DbName, dbField.Value)); } } insertSqlSb.AppendFormat(") values({0})", valueSqlSb); var affectCount = 0; using (var cnn = new MySqlConnection(cnnStr)) { using (var cmd = new MySqlCommand(insertSqlSb.ToString(), cnn)) { cnn.Open(); cmd.Parameters.AddRange(paras.ToArray()); affectCount = cmd.ExecuteNonQuery(); } } return affectCount; }
上面可看到 get 和 post 方法是脱离业务的,全部业务都在 sqlJson 配置和 前端返回的 json 数据,从而实现了后台配置化操做数据库,不需建立额外的对象,就能够把前端返回的json 数据, 直接持久化到数据库了。bash
这个类是 EasyJsonToSql 入口,用来获取 SelectBuilder 和 DbBuilder 对象。
1) 获取 SelectBuilder
const string sqlJson = @" { ""Select"":""user.*"", ""From"":""BasUser user"", ""Where"":{ ""Fields"":[ {""Name"":""Name"",""Cp"":""like""} ] }, ""OrderBy"":{""Default"":""Id""}, ""ID"":""Id"", ""Table"":""BasUser"", ""Insert"":{ ""Fields"":[ {""Name"":""Name"",""IsIgnore"":""false""} ] } } "; var sqlconfig = JsonConvert.DeserializeObject<SqlConfig>(sqlJson); var builder = new Proxy().ToSelectBuilder(sqlconfig, nameValues);
2) 获取 DbBuilder
// 插入数据 var postJson = @"{""master"":{""inserted"":[{""data"":{""Name"":""abc1""}}]}}"; var jobj = JObject.Parse(postJson); var sqlconfig = JsonConvert.DeserializeObject<SqlConfig>(sqlJson); var builder = new Proxy().ToDbBuilders(sqlconfig, jobj);
该类负责处理查询分析,把 json 转换成查询的 sql。
1) Data[SelectBuilderData]: 生成的 sql 对象。
1) AddWhere: 添加 where 条件 sql,
builder.AddWhere("And table1.Id = 1"); builder.AddWhere("And table1.Id = @Id").AddParam("Id",1);
2) AddParam: 添加参数, builder.AddParam("Id",1)
var data = builder.Data; var sql = string.format("Select {0} From {1} Where {2}", data.Select, data.From, data.Where);
该类负责处理增删改分析,把 json 转换成增删改的 sql。
1) Data[BuilderData]: 生成的 sql 对象。
1) AddChild: 添加子表对象。
2) AddWhere: 添加 where 条件 sql;
builder.AddWhere("And table1.Id = 1"); builder.AddWhere("And table1.Id = @Id").AddParam("Id", 1);
3) AddParam: 添加参数, builder.AddParam("Id",1)
;
该类保存 select、from、where、insert、update、delete, 以及子表、依赖关系、自增字段、主键等 sql 相关对象,标准化 sql 配置以便脱离具体业务。
用来初始化 SelectBuilder 和 DBBuilder, 实现标准化的增删改查操做。
上面就是用 json 配置的来反射出 SqlConfig, var sqlconfig = JsonConvert.DeserializeObject<SqlConfig>(sqlJson);
public class SqlConfig { public SqlConfig() { this.Where = new Where(); this.Children = new List<SqlConfig>(); this.OrderBy = new OrderBy(); this.GroupBy = new GroupBy(); this.Dependency = new Dependency(); this.Insert = new Insert(); this.Update = new Update(); this.Delete = new Delete(); this.SingleQuery = new SingleQuery(); this.Export = new Export(); this.Import = new Import(); this.BillCodeRule = new BillCodeRule(); } private string _settingName; /// <summary> /// 配置名称,默认和表名一致,通常不会用到,方法之后扩展,如一个配置文件出现相同的表时,用来区分不一样的配置 /// </summary> public string SettingName { get { if (string.IsNullOrEmpty(_settingName)) { _settingName = Table; } return _settingName; } set { _settingName = value; } } #region 查询配置 /// <summary> /// 查询的字段 /// </summary> public string Select { get; set; } /// <summary> /// 查询的表名以及关联的表名,如 left join, right join /// </summary> public string From { get; set; } /// <summary> /// 查询的条件 /// 前端返回的查询条件,只有出如今这些配置好的字段,才会生成为了 sql 的 where 条件, /// 没出现的字段会被忽略 /// </summary> public Where Where { get; set; } /// <summary> /// 分页时必须会乃至的排序规则 /// </summary> public OrderBy OrderBy { get; set; } public GroupBy GroupBy { get; set; } /// <summary> /// 页码 /// </summary> public int PageNumber { get; set; } /// <summary> /// 页大小 /// </summary> public int PageSize { get; set; } #endregion 查询配置 /// <summary> /// 指定该配置所属于的表 /// </summary> public string Table { get; set; } #region 增删改配置 /// <summary> /// 对应前端返回的 json 格式数据的键名 /// e.g.: {master:{inserted:[{data:{}}]}} 中的 master 就是这里要对应的 JsonName /// 注意默认主表的 jsonName 是 master, 因此主表通常可省略不写, 但子表必须得指定 /// </summary> public string JsonName { get; set; } /// <summary> /// 自增的字段,指定了自增的字段,在 insert 时会自动忽略该字段 /// </summary> public string ID { get; set; } /// <summary> /// 主键, 在保存成功后会返回主键的值; /// </summary> public string PKs { get; set; } /// <summary> /// 惟一值的字段,对应数据库 unique, 在 insert,update 前会判断是否已存在 /// </summary> public string Uniques { get; set; } /// <summary> /// 惟一值的字段的值是否容许为空 /// </summary> public string UniqueAllowEmptys { get; set; } /// <summary> /// 所属的父级配置, 在 xml 中不用指定,程序会自动分析 /// </summary> public SqlConfig Parent { get; set; } /// <summary> /// 包含的子级配置, 即子表的配置,须要在 xml 中配置 /// </summary> public List<SqlConfig> Children { get; set; } /// <summary> /// 依赖父表的字段 /// </summary> public Dependency Dependency { get; set; } /// <summary> /// insert 的配置 /// </summary> public Insert Insert { get; set; } /// <summary> /// update 的配置 /// </summary> public Update Update { get; set; } /// <summary> /// delete 的配置 /// </summary> public Delete Delete { get; set; } #endregion /// <summary> /// 单条记录查询的配置,通常用在配置列表双击弹出那条记录的获取的 sql /// </summary> public SingleQuery SingleQuery { get; set; } /// <summary> /// 导出配置 /// </summary> public Export Export { get; set; } /// <summary> /// 导入配置 /// </summary> public Import Import { get; set; } /// <summary> /// 是否物理删除? /// </summary> public bool DeleteAnyway { get; set; } /// <summary> /// 表单编码的生成配置 /// </summary> public BillCodeRule BillCodeRule { get; set; } }
能够用 xml、json 或对象来配置表关系,若是用了 xml 或 json配置, 把它反射成对象便可。
1) xml 配置
string sqlXml = @" <SqlConfig> <Select> user.* </Select> <From> BasUser user </From> <Where> <Fields> <Field Name=""Name"" Cp=""like""></Field> </Fields> </Where> <OrderBy> <Default>Id</Default> </OrderBy> <IDs>Id</IDs> <PKs>Id</PKs> <Table>BasUser</Table> <Insert> <Fields> <Field Name=""Name"" IsIgnore=""false""></Field> </Fields> </Insert> </SqlConfig> ";
2) json 配置
string sqlJson = @" { ""Select"":""user.*"", ""From"":""BasUser user"", ""Where"":{ ""Fields"":[ {""Name"":""Name"",""Cp"":""like""} ] }, ""OrderBy"":{""Default"":""Id""}, ""ID"":""Id"", ""PKs"":""Id"", ""Table"":""BasUser"", ""Insert"":{ ""Fields"":[ {""Name"":""Name"",""IsIgnore"":""false""} ] } } "; var sqlconfig = JsonConvert.DeserializeObject<SqlConfig>(sqlJson);
初始化登陆名:admin, 密码: 123