【开源.NET】轻量级内容管理框架Grissom.CMS(第三篇解析配置文件和数据以转换成 sql)
该篇是 Grissom.CMS 框架系列文章的第三篇, 主要介绍框架用到的核心库 EasyJsonToSql, 把标准的配置文件和数据结构解析成可执行的 sql。
该框架能实现自动化增删改查得益于 EasyJsonToSql 类库的功能:解析配置好的表结构和要进行数据库操作的数据,生成 sql,减少普通的增删改查代码量,简化“数据库 - 后端- 前端”之间的交互。
【开源.NET】 轻量级内容管理框架Grissom.CMS(第一篇分享一个前后端分离框架)
【开源.NET】 轻量级内容管理框架Grissom.CMS(第二篇前后端交互数据结构分析)
【开源.NET】 轻量级内容管理框架Grissom.CMS(第三篇解析配置文件和数据以转换成 sql)
安装
Nuget 命令
Install-Package EasyJsonToSql
或Nuget 界面搜索: EasyJsonToSql
或下载源码(看文章底部)
Kick Start
- 假设有一张表
CREATE TABLE `BasUser` (
`Id` bigint(20) NOT NULL AUTO_INCREMENT,
`Name` varchar(64) DEFAULT NULL,
PRIMARY KEY (`Id`)
);
- 后台配置 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""}
]
}
}
";
- 查询 reqeust url:
http://localhost:9819/api/user/get?name=test
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"}]
- 新增 post url:
http://localhost:9819/api/user/post
, form data:{"master":{"inserted":[{"data":{"Name":"test1"}}]}}
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 数据, 直接持久化到数据库了。
简介
Proxy
这个类是 EasyJsonToSql 入口,用来获取 SelectBuilder 和 DbBuilder 对象。
方法
- 获取 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);
- 获取 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);
SelectBuilder
该类负责处理查询分析,把 json 转换成查询的 sql。
关键属性
- Data[SelectBuilderData]: 生成的 sql 对象。
常用方法
- AddWhere: 添加 where 条件 sql,
builder.AddWhere("And table1.Id = 1");
builder.AddWhere("And table1.Id = @Id").AddParam("Id",1);
- 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);
DbBuilder
该类负责处理增删改分析,把 json 转换成增删改的 sql。
关键属性
- Data[BuilderData]: 生成的 sql 对象。
常用方法
- AddChild: 添加子表对象。
- AddWhere: 添加 where 条件 sql;
builder.AddWhere("And table1.Id = 1");
builder.AddWhere("And table1.Id = @Id").AddParam("Id", 1);
- AddParam: 添加参数,
builder.AddParam("Id",1)
;
SqlConfig
该类保存 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配置, 把它反射成对象即可。
- 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>
";
- 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);
Grissom.CMS框架源码 https://github.com/grissomlau/Grissom.CMS
初始化登录名:admin, 密码: 123
EasyJsonToSql类库源码 https://github.com/grissomlau/EasyJsonToSql
【开源.NET】轻量级内容管理框架Grissom.CMS(第三篇解析配置文件和数据以转换成 sql)的更多相关文章
- 【开源.NET】 轻量级内容管理框架Grissom.CMS(第二篇前后端交互数据结构分析)
这是 CMS 框架系列文章的第二篇,第一篇开源了该框架的代码和简要介绍了框架的目的.作用和思想,这篇主要解析如何把sql 转成标准 xml 配置文件和把前端post的增删改数据规范成方便后台解析的结构 ...
- 【开源.NET】 分享一个前后端分离的轻量级内容管理框架
开发框架要考虑的面太多了:安全.稳定.性能.效率.扩展.整洁,还要经得起实践的考验,从零开发一个可用的框架,是很耗时费神的工作.网上很多开源的框架,为何还要自己开发?我是基于以下两点: 没找到合适的: ...
- jQuery、JS读取xml文件里的内容(JS先通过document.implementation.createDocument方法将xml转换成document对象,jQuery将读取到的xml转成table)
xml文件:test.xml <?xml version="1.0"?> <note> <to>George</to> <fr ...
- (一)熟悉执行流程——基于ThinkPHP3.2的内容管理框架OneThink学习
ThinkPHP作为国内具有代表性的PHP框架,经过多年的发展,受到越来越多公司与开发者的青睐.我也在忙里偷闲中抽出部分时间,来学习这个优秀的框架.在开始学习这个框架时,最好通过实例来学习,更容易结合 ...
- Android轻量级日志管理框架
代码地址如下:http://www.demodashi.com/demo/12134.html ViseLog Android 轻量级日志框架,使用森林对象维护不同的日志树进行日志输出,可以是Logc ...
- 商城04——门户网站介绍&商城首页搭建&内容系统创建&CMS实现
1. 课程计划 1.门户系统的搭建 2.显示商城首页 3.内容管理系统的实现 a) 内容分类管理 b) 内容管理 2. 门户系统的搭建 2.1. 什么是门户系统 从广义上来说,它将各种应用系 ...
- [开源框架推荐]Icepdf:纯java的pdf文档的提取和转换库
ICEpdf 是一个轻量级的开源 Java 语言的 PDF 类库.通过 ICEpdf 可以用来浏览.内容提取和转换 PDF 文档,而无须一些本地PDF库的支持. 可以用来做什么? 1.从pdf文件中提 ...
- .NET Core实战项目之CMS 第三章 入门篇-源码解析配置文件及依赖注入
作者:依乐祝 原文链接:https://www.cnblogs.com/yilezhu/p/9998021.html 写在前面 上篇文章我给大家讲解了ASP.NET Core的概念及为什么使用它,接着 ...
- .NET平台开源项目速览(20)Newlife.Core中简单灵活的配置文件
记得5年前开始拼命翻读X组件的源码,特别是XCode,但对Newlife.Core 的东西了解很少,最多只是会用用,而且用到的只是九牛一毛.里面好用的东西太多了. 最近一年时间,零零散散又学了很多,也 ...
随机推荐
- 把windows的bat用好了,也很不错
taskkill /f /t /im nginx.exe cp2nginx xcopy /e /i /y “D:\workspace\workspace1\aff\WebContent” “D:\ng ...
- iOS 之 调试、解决BUG
iOS 解决一个复杂bug 之 计分卡 iOS 调试 之 打印 iOS 错误之 NSObject .CGFloat iOS bug 之 H5 页面没有弹出提示框 iOS 日志工具 CocoaLumbe ...
- centos 6.5下安装文件上传下载服务
centos 6.5下安装文件上传下载服务 由于每次在CentOS中要下载一些配置文件到物理机,和上传一些文件到服务器,导致来回的开启ftp软件有点麻烦,这里我们可以使用文件上传下载服务,来解决上传和 ...
- JavaScript特效制作经典精讲(案例入门详解、可直接粘贴拷贝运行、史上最牛案例)
技巧一.添加链接提示 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http:// ...
- NodeMCU之旅(一):构建、刷入固件,上传代码
扬帆起航 本系列文章将试图实现,使用Web页面远程点亮led.具体包括: 在NodeMCU上搭建HTTP服务器,使其可以通过Web页面配置要接入的网络. 在配置页面可以显示附近中英网络名与信号强度. ...
- BNU Online Judge-29140
题目链接 http://www.bnuoj.com/bnuoj/problem_show.php?pid=29140 看到这样的题,应该想到an 与an-1 的关系,他们是会有关系的你要去找 代码 ...
- inline「一」:从 image 底部白边初识 line-height
本文首发于个人博客 http://www.lijundong.com/image-and-line-height/ 今天在做一个静态页面时,图片底部出现一条 3px 高度的白边,既不是 margin ...
- loadrunner:关联操作
文章以实例讲解loadrunner中的关联操作,内容包括:自动关联.手动关联和关联规则的设置. 1.1.1 准备工作 在web tours项目默认设置里,登录操作是没有生成sessionID的 ...
- Docker环境中部署DzzOffice 1.2.5.2
整体思路: 1.官方获取mysql.php+apache镜像: 2.基于php+apache,创建DzzOffice镜像: 3.启动mysql镜像: 4.启动DzzOffice镜像,链接mysql镜像 ...
- array_count_values:返回数组中所有值出现的次数
$arr1 = ['a','b','c','d','e','e','a','a']; $arr = array_count_values($arr1); echo '<pre>'; p ...