SelectTable.cs 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008
  1. // 大名科技(天津)有限公司版权所有 电话:18020030720 QQ:515096995
  2. //
  3. // 此源代码遵循位于源代码树根目录中的 LICENSE 文件的许可证
  4. namespace Admin.NET.Core.Service;
  5. using AspectCore.Extensions.Reflection;
  6. using NewLife.Data;
  7. using Newtonsoft.Json.Linq;
  8. using Newtonsoft.Json.Schema;
  9. using OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
  10. using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
  11. using SqlSugar;
  12. using StackExchange.Redis;
  13. using System;
  14. using System.Collections;
  15. using System.Collections.Generic;
  16. using System.Dynamic;
  17. using System.Linq;
  18. using System.Text.RegularExpressions;
  19. using static OfficeOpenXml.ExcelErrorValue;
  20. /// <summary>
  21. ///
  22. /// </summary>
  23. public class SelectTable : ISingleton
  24. {
  25. private readonly IdentityService _identitySvc;
  26. private readonly TableMapper _tableMapper;
  27. private readonly ISqlSugarClient _db;
  28. /// <summary>
  29. ///
  30. /// </summary>
  31. /// <param name="identityService"></param>
  32. /// <param name="tableMapper"></param>
  33. /// <param name="dbClient"></param>
  34. public SelectTable(IdentityService identityService, TableMapper tableMapper, ISqlSugarClient dbClient)
  35. {
  36. _identitySvc = identityService;
  37. _tableMapper = tableMapper;
  38. _db = dbClient;
  39. }
  40. /// <summary>
  41. /// 判断表名是否正确,如果不正确则抛异常
  42. /// </summary>
  43. /// <param name="table"></param>
  44. /// <returns></returns>
  45. public virtual bool IsTable(string table)
  46. {
  47. if (_db.DbMaintenance.GetTableInfoList().Any(it => it.Name.Equals(table, StringComparison.CurrentCultureIgnoreCase)))
  48. return true;
  49. else
  50. throw new Exception($"表名【{table}】不正确!");
  51. }
  52. /// <summary>
  53. /// 判断表的列名是否正确,如果不正确则抛异常,更早地暴露给调用方
  54. /// </summary>
  55. /// <param name="table"></param>
  56. /// <param name="col"></param>
  57. /// <returns></returns>
  58. public virtual bool IsCol(string table, string col)
  59. {
  60. if (_db.DbMaintenance.GetColumnInfosByTableName(table).Any(it => it.DbColumnName.Equals(col, StringComparison.CurrentCultureIgnoreCase)))
  61. return true;
  62. else
  63. throw new Exception($"表【{table}】不存在列【{col}】!请检查输入参数");
  64. }
  65. /// <summary>
  66. ///
  67. /// </summary>
  68. /// <param name="subtable"></param>
  69. /// <param name="page"></param>
  70. /// <param name="count"></param>
  71. /// <param name="json"></param>
  72. /// <param name="dd"></param>
  73. /// <returns></returns>
  74. public virtual Tuple<dynamic, int> GetTableData(string subtable, int page, int count, int query, string json, JObject dd)
  75. {
  76. var role = _identitySvc.GetSelectRole(subtable);
  77. if (!role.Item1)//没有权限返回异常
  78. {
  79. throw new Exception(role.Item2);
  80. }
  81. string selectrole = role.Item2;
  82. subtable = _tableMapper.GetTableName(subtable);
  83. JObject values = JObject.Parse(json);
  84. page = values["page"] == null ? page : int.Parse(values["page"].ToString());
  85. count = values["count"] == null ? count : int.Parse(values["count"].ToString());
  86. query = values["query"] == null ? query : int.Parse(values["query"].ToString());
  87. values.Remove("page");
  88. values.Remove("count");
  89. var tb = SugarQueryable(subtable, selectrole, values, dd);
  90. if (query == 1)//1-总数
  91. return new Tuple<dynamic, int>(null, tb.MergeTable().Count());
  92. else
  93. {
  94. if (page > 0)//分页
  95. {
  96. int total = 0;
  97. if (query == 0)//0-对象
  98. return new Tuple<dynamic, int>(tb.ToPageList(page, count), total);
  99. else
  100. //2-以上全部
  101. return new Tuple<dynamic, int>(tb.ToPageList(page, count, ref total), total);
  102. }
  103. else//列表
  104. {
  105. IList l = tb.ToList();
  106. if (query == 0)
  107. return new Tuple<dynamic, int>(l, 0);
  108. else
  109. return new Tuple<dynamic, int>(l, l.Count);
  110. }
  111. }
  112. }
  113. /// <summary>
  114. /// 解析并查询
  115. /// </summary>
  116. /// <param name="query"></param>
  117. /// <returns></returns>
  118. public virtual JObject Query(string queryJson)
  119. {
  120. JObject resultObj = new JObject();
  121. JObject queryJobj = JObject.Parse(queryJson);
  122. resultObj = Query(queryJobj);
  123. return resultObj;
  124. }
  125. /// <summary>
  126. /// 单表查询
  127. /// </summary>
  128. /// <param name="queryObj"></param>
  129. /// <param name="nodeName">返回数据的节点名称 默认为 infos</param>
  130. /// <returns></returns>
  131. public virtual JObject QuerySingle(JObject queryObj, string nodeName = "infos")
  132. {
  133. JObject resultObj = new JObject();
  134. int total = 0;
  135. foreach (var item in queryObj)
  136. {
  137. string key = item.Key.Trim();
  138. if (key.EndsWith("[]"))
  139. {
  140. total = QuerySingleList(resultObj, item, nodeName);
  141. }
  142. else if (key.Equals("func"))
  143. {
  144. ExecFunc(resultObj, item);
  145. }
  146. else if (key.Equals("total@") || key.Equals("total"))
  147. {
  148. resultObj.Add("total", total);
  149. }
  150. }
  151. return resultObj;
  152. }
  153. /// <summary>
  154. /// 获取查询语句
  155. /// </summary>
  156. /// <param name="queryObj"></param>
  157. /// <returns></returns>
  158. public virtual string ToSql(JObject queryObj)
  159. {
  160. foreach (var item in queryObj)
  161. {
  162. string key = item.Key.Trim();
  163. if (key.EndsWith("[]"))
  164. {
  165. return ToSql(item);
  166. }
  167. }
  168. return string.Empty;
  169. }
  170. /// <summary>
  171. /// 解析并查询
  172. /// </summary>
  173. /// <param name="query"></param>
  174. /// <returns></returns>
  175. public virtual JObject Query(JObject queryObj)
  176. {
  177. JObject resultObj = new JObject();
  178. int total;
  179. foreach (var item in queryObj)
  180. {
  181. string key = item.Key.Trim();
  182. if (key.Equals("[]"))
  183. {
  184. total = QueryMoreList(resultObj, item);
  185. resultObj.Add("total", total);//只要是列表查询都自动返回总数
  186. }
  187. else if (key.EndsWith("[]"))
  188. {
  189. total = QuerySingleList(resultObj, item);
  190. }
  191. else if (key.Equals("func"))
  192. {
  193. ExecFunc(resultObj, item);
  194. }
  195. else if (key.Equals("total@") || key.Equals("total"))
  196. {
  197. //resultObj.Add("total", total);
  198. continue;
  199. }
  200. else
  201. {
  202. var template = GetFirstData(key, item.Value.ToString(), resultObj);
  203. if (template != null)
  204. {
  205. resultObj.Add(key, JToken.FromObject(template));
  206. }
  207. }
  208. }
  209. return resultObj;
  210. }
  211. //动态调用方法
  212. private object ExecFunc(string funcname, object[] param, Type[] types)
  213. {
  214. var method = typeof(FuncList).GetMethod(funcname);
  215. var reflector = method.GetReflector();
  216. var result = reflector.Invoke(new FuncList(), param);
  217. return result;
  218. }
  219. //生成sql
  220. private string ToSql(string subtable, int page, int count, int query, string json)
  221. {
  222. JObject values = JObject.Parse(json);
  223. page = values["page"] == null ? page : int.Parse(values["page"].ToString());
  224. count = values["count"] == null ? count : int.Parse(values["count"].ToString());
  225. query = values["query"] == null ? query : int.Parse(values["query"].ToString());
  226. values.Remove("page");
  227. values.Remove("count");
  228. subtable = _tableMapper.GetTableName(subtable);
  229. var tb = SugarQueryable(subtable, "*", values, null);
  230. var sqlObj = tb.Skip((page - 1) * count).Take(10).ToSql();
  231. return sqlObj.Key;
  232. }
  233. //
  234. private dynamic GetFirstData(string subtable, string json, JObject job)
  235. {
  236. var role = _identitySvc.GetSelectRole(subtable);
  237. if (!role.Item1)//没有权限返回异常
  238. {
  239. throw new Exception(role.Item2);
  240. }
  241. string selectrole = role.Item2;
  242. subtable = _tableMapper.GetTableName(subtable);
  243. JObject values = JObject.Parse(json);
  244. values.Remove("page");
  245. values.Remove("count");
  246. //todo *
  247. var tb = SugarQueryable(subtable, selectrole, values, job).First();
  248. var dic = (IDictionary<string, object>)tb;
  249. foreach (var item in values.Properties().Where(it => it.Name.EndsWith("()")))
  250. {
  251. if (item.Value.HasValue())
  252. {
  253. string func = item.Value.ToString().Substring(0, item.Value.ToString().IndexOf("("));
  254. string param = item.Value.ToString().Substring(item.Value.ToString().IndexOf("(") + 1).TrimEnd(')');
  255. var types = new List<Type>();
  256. var paramss = new List<object>();
  257. foreach (var va in param.Split(','))
  258. {
  259. types.Add(typeof(object));
  260. paramss.Add(tb.Where(it => it.Key.Equals(va)).Select(i => i.Value));
  261. }
  262. dic[item.Name] = ExecFunc(func, paramss.ToArray(), types.ToArray());
  263. }
  264. }
  265. return tb;
  266. }
  267. //单表查询,返回的数据在指定的NodeName节点
  268. private int QuerySingleList(JObject resultObj, KeyValuePair<string, JToken> item, string nodeName)
  269. {
  270. string key = item.Key.Trim();
  271. var jb = JObject.Parse(item.Value.ToString());
  272. int page = jb["page"] == null ? 0 : int.Parse(jb["page"].ToString());
  273. int count = jb["count"] == null ? 10 : int.Parse(jb["count"].ToString());
  274. int query = jb["query"] == null ? 2 : int.Parse(jb["query"].ToString());//默认输出数据和数量
  275. int total = 0;
  276. jb.Remove("page"); jb.Remove("count"); jb.Remove("query");
  277. var htt = new JArray();
  278. foreach (var t in jb)
  279. {
  280. var datas = GetTableData(t.Key, page, count, query, t.Value.ToString(), null);
  281. if (query > 0)
  282. {
  283. total = datas.Item2;
  284. }
  285. foreach (var data in datas.Item1)
  286. {
  287. htt.Add(JToken.FromObject(data));
  288. }
  289. }
  290. if (!string.IsNullOrEmpty(nodeName))
  291. {
  292. resultObj.Add(nodeName, htt);
  293. }
  294. else
  295. resultObj.Add(key, htt);
  296. return total;
  297. }
  298. //生成sql
  299. private string ToSql(KeyValuePair<string, JToken> item)
  300. {
  301. string key = item.Key.Trim();
  302. var jb = JObject.Parse(item.Value.ToString());
  303. int page = jb["page"] == null ? 0 : int.Parse(jb["page"].ToString());
  304. int count = jb["count"] == null ? 10 : int.Parse(jb["count"].ToString());
  305. int query = jb["query"] == null ? 2 : int.Parse(jb["query"].ToString());//默认输出数据和数量
  306. jb.Remove("page"); jb.Remove("count"); jb.Remove("query");
  307. var htt = new JArray();
  308. foreach (var t in jb)
  309. {
  310. return ToSql(t.Key, page, count, query, t.Value.ToString());
  311. }
  312. return string.Empty;
  313. }
  314. //单表查询
  315. private int QuerySingleList(JObject resultObj, KeyValuePair<string, JToken> item)
  316. {
  317. string key = item.Key.Trim();
  318. return QuerySingleList(resultObj, item, key);
  319. }
  320. //多列表查询
  321. private int QueryMoreList(JObject resultObj, KeyValuePair<string, JToken> item)
  322. {
  323. int total = 0;
  324. var jb = JObject.Parse(item.Value.ToString());
  325. var page = jb["page"] == null ? 0 : int.Parse(jb["page"].ToString());
  326. var count = jb["count"] == null ? 10 : int.Parse(jb["count"].ToString());
  327. var query = jb["query"] == null ? 2 : int.Parse(jb["query"].ToString());//默认输出数据和数量
  328. jb.Remove("page"); jb.Remove("count"); jb.Remove("query");
  329. var htt = new JArray();
  330. List<string> tables = new List<string>(), where = new List<string>();
  331. foreach (var t in jb)
  332. {
  333. tables.Add(t.Key); where.Add(t.Value.ToString());
  334. }
  335. if (tables.Count > 0)
  336. {
  337. string table = tables[0];
  338. var temp = GetTableData(table, page, count, query, where[0], null);
  339. if (query > 0)
  340. {
  341. total = temp.Item2;
  342. }
  343. foreach (var dd in temp.Item1)
  344. {
  345. var zht = new JObject();
  346. zht.Add(table, JToken.FromObject(dd));
  347. for (int i = 1; i < tables.Count; i++)
  348. {
  349. string subtable = tables[i];
  350. if (subtable.EndsWith("[]"))
  351. {
  352. subtable = subtable.TrimEnd("[]".ToCharArray());
  353. var jbb = JObject.Parse(where[i]);
  354. page = jbb["page"] == null ? 0 : int.Parse(jbb["page"].ToString());
  355. count = jbb["count"] == null ? 0 : int.Parse(jbb["count"].ToString());
  356. var lt = new JArray();
  357. foreach (var d in GetTableData(subtable, page, count, query, jbb[subtable].ToString(), zht).Item1)
  358. {
  359. lt.Add(JToken.FromObject(d));
  360. }
  361. zht.Add(tables[i], lt);
  362. }
  363. else
  364. {
  365. var ddf = GetFirstData(subtable, where[i].ToString(), zht);
  366. if (ddf != null)
  367. {
  368. zht.Add(subtable, JToken.FromObject(ddf));
  369. }
  370. }
  371. }
  372. htt.Add(zht);
  373. }
  374. }
  375. if (query != 1)
  376. {
  377. resultObj.Add("[]", htt);
  378. }
  379. //分页自动添加当前页数和数量
  380. if (page > 0 && count > 0)
  381. {
  382. resultObj.Add("page", page);
  383. resultObj.Add("count", count);
  384. resultObj.Add("max", total / count + 1);
  385. }
  386. return total;
  387. }
  388. //执行方法
  389. private void ExecFunc(JObject resultObj, KeyValuePair<string, JToken> item)
  390. {
  391. JObject jb = JObject.Parse(item.Value.ToString());
  392. Type type = typeof(FuncList);
  393. var dataJObj = new JObject();
  394. foreach (var f in jb)
  395. {
  396. var types = new List<Type>();
  397. var param = new List<object>();
  398. foreach (var va in JArray.Parse(f.Value.ToString()))
  399. {
  400. types.Add(typeof(object));
  401. param.Add(va);
  402. }
  403. dataJObj.Add(f.Key, JToken.FromObject(ExecFunc(f.Key, param.ToArray(), types.ToArray())));
  404. }
  405. resultObj.Add("func", dataJObj);
  406. }
  407. /// <summary>
  408. /// 构造查询过程
  409. /// </summary>
  410. /// <param name="subtable"></param>
  411. /// <param name="selectrole"></param>
  412. /// <param name="values"></param>
  413. /// <param name="dd"></param>
  414. /// <returns></returns>
  415. private ISugarQueryable<ExpandoObject> SugarQueryable(string subtable, string selectrole, JObject values, JObject dd)
  416. {
  417. IsTable(subtable);
  418. var tb = _db.Queryable(subtable, "tb");
  419. //select
  420. if (values["@column"].HasValue())
  421. {
  422. ProcessColumn(subtable, selectrole, values, tb);
  423. }
  424. else
  425. {
  426. tb.Select(selectrole);
  427. }
  428. //前几行
  429. ProcessLimit(values, tb);
  430. //where
  431. ProcessWhere(subtable, values, tb, dd);
  432. //排序
  433. ProcessOrder(subtable, values, tb);
  434. //分组
  435. PrccessGroup(subtable, values, tb);
  436. //Having
  437. ProcessHaving(values, tb);
  438. return tb;
  439. }
  440. //处理字段重命名 "@column":"toId:parentId",对应SQL是toId AS parentId,将查询的字段toId变为parentId返回
  441. private void ProcessColumn(string subtable, string selectrole, JObject values, ISugarQueryable<ExpandoObject> tb)
  442. {
  443. var str = new System.Text.StringBuilder(100);
  444. foreach (var item in values["@column"].ToString().Split(','))
  445. {
  446. string[] ziduan = item.Split(':');
  447. string colName = ziduan[0];
  448. var ma = new Regex(@"\((\w+)\)").Match(colName);
  449. //处理max,min这样的函数
  450. if (ma.Success && ma.Groups.Count > 1)
  451. {
  452. colName = ma.Groups[1].Value;
  453. }
  454. //判断列表是否有权限 sum(1),sum(*),Count(1)这样的值直接有效
  455. if (colName == "*" || int.TryParse(colName, out int colNumber) || (IsCol(subtable, colName) && _identitySvc.ColIsRole(colName, selectrole.Split(','))))
  456. {
  457. if (ziduan.Length > 1)
  458. {
  459. if (ziduan[1].Length > 20)
  460. {
  461. throw new Exception("别名不能超过20个字符");
  462. }
  463. str.Append(ziduan[0] + " as `" + ReplaceSQLChar(ziduan[1]) + "`,");
  464. }
  465. //不对函数加``,解决sum(*),Count(1)等不能使用的问题
  466. else if (ziduan[0].Contains('('))
  467. {
  468. str.Append(ziduan[0] + ",");
  469. }
  470. else
  471. str.Append("`" + ziduan[0] + "`" + ",");
  472. }
  473. }
  474. if (string.IsNullOrEmpty(str.ToString()))
  475. {
  476. throw new Exception($"表名{subtable}没有可查询的字段!");
  477. }
  478. tb.Select(str.ToString().TrimEnd(','));
  479. }
  480. /// <summary>
  481. /// 构造查询条件 where
  482. /// </summary>
  483. /// <param name="subtable"></param>
  484. /// <param name="values"></param>
  485. /// <param name="tb"></param>
  486. /// <param name="dd"></param>
  487. private void ProcessWhere(string subtable, JObject values, ISugarQueryable<ExpandoObject> tb, JObject dd)
  488. {
  489. List<IConditionalModel> conModels = new List<IConditionalModel>();
  490. if (values["identity"].HasValue())
  491. {
  492. conModels.Add(new ConditionalModel() { FieldName = values["identity"].ToString(), ConditionalType = ConditionalType.Equal, FieldValue = _identitySvc.GetUserIdentity() });
  493. }
  494. foreach (var va in values)
  495. {
  496. string key = va.Key.Trim();
  497. string fieldValue = va.Value.ToString();
  498. if (key.StartsWith("@"))
  499. {
  500. continue;
  501. }
  502. if (key.EndsWith("$"))//模糊查询
  503. {
  504. FuzzyQuery(subtable, conModels, va);
  505. }
  506. else if (key.EndsWith("{}"))//逻辑运算
  507. {
  508. ConditionQuery(subtable, conModels, va);
  509. }
  510. else if (key.EndsWith("%"))//bwtween查询
  511. {
  512. ConditionBetween(subtable, conModels, va);
  513. }
  514. else if (key.EndsWith("@") && dd != null) // 关联上一个table
  515. {
  516. string[] str = fieldValue.Split('/', StringSplitOptions.RemoveEmptyEntries);
  517. string value = string.Empty;
  518. if (str.Length == 3)
  519. {
  520. value = dd[str[1]][str[2]].ToString();
  521. }
  522. else if (str.Length == 2)
  523. {
  524. value = dd[str[0]][str[1]].ToString();
  525. }
  526. conModels.Add(new ConditionalModel() { FieldName = key.TrimEnd('@'), ConditionalType = ConditionalType.Equal, FieldValue = value });
  527. }
  528. else if (key.EndsWith("~"))//不等于
  529. {
  530. conModels.Add(new ConditionalModel() { FieldName = key.TrimEnd('~'), ConditionalType = ConditionalType.NoEqual, FieldValue = fieldValue });
  531. }
  532. else if (IsCol(subtable, key)) //其他where条件
  533. {
  534. if (string.IsNullOrEmpty(fieldValue))
  535. {
  536. conModels.Add(new ConditionalModel() { FieldName = key, ConditionalType = ConditionalType.IsNullOrEmpty });//增加null、""匹配
  537. }
  538. else
  539. {
  540. conModels.Add(new ConditionalModel() { FieldName = key, ConditionalType = ConditionalType.Equal, FieldValue = fieldValue });
  541. }
  542. }
  543. }
  544. tb.Where(conModels);
  545. }
  546. // "@having":"function0(...)?value0;function1(...)?value1;function2(...)?value2...",
  547. // SQL函数条件,一般和 @group一起用,函数一般在 @column里声明
  548. private void ProcessHaving(JObject values, ISugarQueryable<ExpandoObject> tb)
  549. {
  550. if (values["@having"].HasValue())
  551. {
  552. List<IConditionalModel> hw = new List<IConditionalModel>();
  553. List<string> havingItems = new List<string>();
  554. if (values["@having"].HasValues)
  555. {
  556. havingItems = values["@having"].Select(p => p.ToString()).ToList();
  557. }
  558. else
  559. {
  560. havingItems.Add(values["@having"].ToString());
  561. }
  562. foreach (var item in havingItems)
  563. {
  564. string and = item.ToString();
  565. var model = new ConditionalModel();
  566. if (and.Contains(">="))
  567. {
  568. model.FieldName = and.Split(new string[] { ">=" }, StringSplitOptions.RemoveEmptyEntries)[0];
  569. model.ConditionalType = ConditionalType.GreaterThanOrEqual;
  570. model.FieldValue = and.Split(new string[] { ">=" }, StringSplitOptions.RemoveEmptyEntries)[1];
  571. }
  572. else if (and.Contains("<="))
  573. {
  574. model.FieldName = and.Split(new string[] { "<=" }, StringSplitOptions.RemoveEmptyEntries)[0];
  575. model.ConditionalType = ConditionalType.LessThanOrEqual;
  576. model.FieldValue = and.Split(new string[] { "<=" }, StringSplitOptions.RemoveEmptyEntries)[1];
  577. }
  578. else if (and.Contains(">"))
  579. {
  580. model.FieldName = and.Split(new string[] { ">" }, StringSplitOptions.RemoveEmptyEntries)[0];
  581. model.ConditionalType = ConditionalType.GreaterThan;
  582. model.FieldValue = and.Split(new string[] { ">" }, StringSplitOptions.RemoveEmptyEntries)[1];
  583. }
  584. else if (and.Contains("<"))
  585. {
  586. model.FieldName = and.Split(new string[] { "<" }, StringSplitOptions.RemoveEmptyEntries)[0];
  587. model.ConditionalType = ConditionalType.LessThan;
  588. model.FieldValue = and.Split(new string[] { "<" }, StringSplitOptions.RemoveEmptyEntries)[1];
  589. }
  590. else if (and.Contains("!="))
  591. {
  592. model.FieldName = and.Split(new string[] { "!=" }, StringSplitOptions.RemoveEmptyEntries)[0];
  593. model.ConditionalType = ConditionalType.NoEqual;
  594. model.FieldValue = and.Split(new string[] { "!=" }, StringSplitOptions.RemoveEmptyEntries)[1];
  595. }
  596. else if (and.Contains("="))
  597. {
  598. model.FieldName = and.Split(new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries)[0];
  599. model.ConditionalType = ConditionalType.Equal;
  600. model.FieldValue = and.Split(new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries)[1];
  601. }
  602. hw.Add(model);
  603. }
  604. //var d = db.Context.Utilities.ConditionalModelToSql(hw);
  605. //tb.Having(d.Key, d.Value);
  606. tb.Having(string.Join(",", havingItems));
  607. }
  608. }
  609. //"@group":"column0,column1...",分组方式。如果 @column里声明了Table的id,则id也必须在 @group中声明;其它情况下必须满足至少一个条件:
  610. //1.分组的key在 @column里声明
  611. //2.Table主键在 @group中声明
  612. private void PrccessGroup(string subtable, JObject values, ISugarQueryable<ExpandoObject> tb)
  613. {
  614. if (values["@group"].HasValue())
  615. {
  616. List<GroupByModel> groupList = new();//多库兼容写法
  617. foreach (var col in values["@group"].ToString().Split(','))
  618. {
  619. if (IsCol(subtable, col))
  620. {
  621. //str.Append(and + ",");
  622. groupList.Add(new GroupByModel() { FieldName = col });
  623. }
  624. }
  625. if (groupList.Any())
  626. {
  627. tb.GroupBy(groupList);
  628. }
  629. }
  630. }
  631. //处理排序 "@order":"name-,id"查询按 name降序、id默认顺序 排序的User数组
  632. private void ProcessOrder(string subtable, JObject values, ISugarQueryable<ExpandoObject> tb)
  633. {
  634. if (values["@order"].HasValue())
  635. {
  636. List<OrderByModel> orderList = new(); //多库兼容写法
  637. foreach (var item in values["@order"].ToString().Split(','))
  638. {
  639. string col = item.Replace("-", "").Replace("+", "").Replace(" desc", "").Replace(" asc", "");//增加对原生排序的支持
  640. if (IsCol(subtable, col))
  641. {
  642. orderList.Add(new OrderByModel()
  643. {
  644. FieldName = col,
  645. OrderByType = item.EndsWith("-") || item.EndsWith(" desc") ? OrderByType.Desc : OrderByType.Asc
  646. });
  647. }
  648. }
  649. if (orderList.Any())
  650. {
  651. tb.OrderBy(orderList);
  652. }
  653. }
  654. }
  655. /// <summary>
  656. /// 表内参数"@count"(int):查询前几行,不能同时使用count和@count函数
  657. /// </summary>
  658. /// <param name="values"></param>
  659. /// <param name="tb"></param>
  660. private void ProcessLimit(JObject values, ISugarQueryable<ExpandoObject> tb)
  661. {
  662. if (values["@count"].HasValue())
  663. {
  664. int c = values["@count"].ToObject<int>();
  665. tb.Take(c);
  666. }
  667. }
  668. //条件查询 "key{}":"条件0,条件1...",条件为任意SQL比较表达式字符串,非Number类型必须用''包含条件的值,如'a'
  669. //&, |, ! 逻辑运算符,对应数据库 SQL 中的 AND, OR, NOT。
  670. // 横或纵与:同一字段的值内条件默认 | 或连接,不同字段的条件默认 & 与连接。
  671. // ① & 可用于"key&{}":"条件"等
  672. // ② | 可用于"key|{}":"条件", "key|{}":[] 等,一般可省略
  673. // ③ ! 可单独使用,如"key!":Object,也可像&,|一样配合其他功能符使用
  674. private void ConditionQuery(string subtable, List<IConditionalModel> conModels, KeyValuePair<string, JToken> va)
  675. {
  676. string vakey = va.Key.Trim();
  677. string field = vakey.TrimEnd("{}".ToCharArray());
  678. if (va.Value.HasValues)
  679. {
  680. List<string> inValues = new List<string>();
  681. foreach (var cm in va.Value)
  682. {
  683. inValues.Add(cm.ToString());
  684. }
  685. conModels.Add(new ConditionalModel()
  686. {
  687. FieldName = field.TrimEnd("!".ToCharArray()),
  688. ConditionalType = field.EndsWith("!") ? ConditionalType.NotIn : ConditionalType.In,
  689. FieldValue = string.Join(",", inValues)
  690. });
  691. }
  692. else
  693. {
  694. var ddt = new List<KeyValuePair<WhereType, ConditionalModel>>();
  695. foreach (var and in va.Value.ToString().Split(','))
  696. {
  697. var model = new ConditionalModel();
  698. model.FieldName = field.TrimEnd("&".ToCharArray());//处理&()的查询方式
  699. if (and.StartsWith(">="))
  700. {
  701. model.ConditionalType = ConditionalType.GreaterThanOrEqual;
  702. model.FieldValue = and.TrimStart(">=".ToCharArray());
  703. }
  704. else if (and.StartsWith("<="))
  705. {
  706. model.ConditionalType = ConditionalType.LessThanOrEqual;
  707. model.FieldValue = and.TrimStart("<=".ToCharArray());
  708. }
  709. else if (and.StartsWith(">"))
  710. {
  711. model.ConditionalType = ConditionalType.GreaterThan;
  712. model.FieldValue = and.TrimStart('>');
  713. }
  714. else if (and.StartsWith("<"))
  715. {
  716. model.ConditionalType = ConditionalType.LessThan;
  717. model.FieldValue = and.TrimStart('<');
  718. }
  719. ddt.Add(new KeyValuePair<WhereType, ConditionalModel>((field.EndsWith("&") ? WhereType.And : WhereType.Or), model));
  720. }
  721. conModels.Add(new ConditionalCollections() { ConditionalList = ddt });
  722. }
  723. }
  724. //"key%":"start,end" => "key%":["start,end"],其中 start 和 end 都只能为 Boolean, Number, String 中的一种,如 "2017-01-01,2019-01-01" ,["1,90000", "82001,100000"] ,可用于连续范围内的筛选
  725. private void ConditionBetween(string subtable, List<IConditionalModel> conModels, KeyValuePair<string, JToken> va)
  726. {
  727. string vakey = va.Key.Trim();
  728. string field = vakey.TrimEnd("%".ToCharArray());
  729. List<string> inValues = new List<string>();
  730. if (va.Value.HasValues)
  731. {
  732. foreach (var cm in va.Value)
  733. {
  734. inValues.Add(cm.ToString());
  735. }
  736. }
  737. else
  738. {
  739. inValues.Add(va.Value.ToString());
  740. }
  741. for (var i = 0; i < inValues.Count; i++)
  742. {
  743. var fileds = inValues[i].Split(',');
  744. if (fileds.Length == 2)
  745. {
  746. var ddt = new List<KeyValuePair<WhereType, ConditionalModel>>();
  747. var leftCondition = new ConditionalModel()
  748. {
  749. FieldName = field,
  750. ConditionalType = ConditionalType.GreaterThanOrEqual,
  751. FieldValue = fileds[0]
  752. };
  753. ddt.Add(new KeyValuePair<WhereType, ConditionalModel>(i == 0 ? WhereType.And : WhereType.Or, leftCondition));
  754. var rightCondition = new ConditionalModel()
  755. {
  756. FieldName = field,
  757. ConditionalType = ConditionalType.LessThanOrEqual,
  758. FieldValue = fileds[1]
  759. };
  760. ddt.Add(new KeyValuePair<WhereType, ConditionalModel>(WhereType.And, rightCondition));
  761. conModels.Add(new ConditionalCollections() { ConditionalList = ddt });
  762. }
  763. }
  764. }
  765. //模糊搜索 "key$":"SQL搜索表达式" => "key$":["SQL搜索表达式"],任意SQL搜索表达式字符串,如 %key%(包含key), key%(以key开始), %k%e%y%(包含字母k,e,y) 等,%表示任意字符
  766. private void FuzzyQuery(string subtable, List<IConditionalModel> conModels, KeyValuePair<string, JToken> va)
  767. {
  768. string vakey = va.Key.Trim();
  769. string fieldValue = va.Value.ToString();
  770. var conditionalType = ConditionalType.Like;
  771. if (IsCol(subtable, vakey.TrimEnd('$')))
  772. {
  773. //支持三种like查询
  774. if (fieldValue.StartsWith("%") && fieldValue.EndsWith("%"))
  775. {
  776. conditionalType = ConditionalType.Like;
  777. }
  778. else if (fieldValue.StartsWith("%"))
  779. {
  780. conditionalType = ConditionalType.LikeRight;
  781. }
  782. else if (fieldValue.EndsWith("%"))
  783. {
  784. conditionalType = ConditionalType.LikeLeft;
  785. }
  786. conModels.Add(new ConditionalModel() { FieldName = vakey.TrimEnd('$'), ConditionalType = conditionalType, FieldValue = fieldValue.TrimEnd("%".ToArray()).TrimStart("%".ToArray()) });
  787. }
  788. }
  789. //处理sql注入
  790. private string ReplaceSQLChar(string str)
  791. {
  792. if (str == String.Empty)
  793. return String.Empty;
  794. str = str.Replace("'", "");
  795. str = str.Replace(";", "");
  796. str = str.Replace(",", "");
  797. str = str.Replace("?", "");
  798. str = str.Replace("<", "");
  799. str = str.Replace(">", "");
  800. str = str.Replace("(", "");
  801. str = str.Replace(")", "");
  802. str = str.Replace("@", "");
  803. str = str.Replace("=", "");
  804. str = str.Replace("+", "");
  805. str = str.Replace("*", "");
  806. str = str.Replace("&", "");
  807. str = str.Replace("#", "");
  808. str = str.Replace("%", "");
  809. str = str.Replace("$", "");
  810. str = str.Replace("\"", "");
  811. //删除与数据库相关的词
  812. str = Regex.Replace(str, "delete from", "", RegexOptions.IgnoreCase);
  813. str = Regex.Replace(str, "drop table", "", RegexOptions.IgnoreCase);
  814. str = Regex.Replace(str, "truncate", "", RegexOptions.IgnoreCase);
  815. str = Regex.Replace(str, "xp_cmdshell", "", RegexOptions.IgnoreCase);
  816. str = Regex.Replace(str, "exec master", "", RegexOptions.IgnoreCase);
  817. str = Regex.Replace(str, "net localgroup administrators", "", RegexOptions.IgnoreCase);
  818. str = Regex.Replace(str, "net user", "", RegexOptions.IgnoreCase);
  819. str = Regex.Replace(str, "-", "", RegexOptions.IgnoreCase);
  820. str = Regex.Replace(str, "truncate", "", RegexOptions.IgnoreCase);
  821. return str;
  822. }
  823. /// <summary>
  824. /// 单条插入
  825. /// </summary>
  826. /// <param name="tableName"></param>
  827. /// <param name="cols"></param>
  828. /// <param name="role"></param>
  829. /// <returns>(各种类型的)id</returns>
  830. public object InsertSingle(string tableName, JObject cols, APIJSON_Role role = null)
  831. {
  832. role ??= _identitySvc.GetRole();
  833. var dt = new Dictionary<string, object>();
  834. foreach (var f in cols)//遍历字段
  835. {
  836. if (//f.Key.ToLower() != "id" && //是否一定要传id
  837. IsCol(tableName, f.Key) &&
  838. (role.Insert.Column.Contains("*") || role.Insert.Column.Contains(f.Key, StringComparer.CurrentCultureIgnoreCase)))
  839. dt.Add(f.Key, FuncList.TransJObjectToSugarPara(f.Value));
  840. }
  841. //如果外部没传id,就后端生成或使用数据库默认值,如果都没有会出错
  842. object id;
  843. if (!dt.ContainsKey("id"))
  844. {
  845. id = YitIdHelper.NextId();//自己生成id的方法,可以由外部传入
  846. dt.Add("id", id);
  847. }
  848. else
  849. {
  850. id = dt["id"];
  851. }
  852. _db.Insertable(dt).AS(tableName).ExecuteCommand();//根据主键类型设置返回雪花或自增,目前返回条数
  853. return id;
  854. }
  855. /// <summary>
  856. /// 为每天记录创建udpate sql
  857. /// </summary>
  858. /// <param name="tableName"></param>
  859. /// <param name="record"></param>
  860. /// <param name="role"></param>
  861. /// <returns></returns>
  862. public int UpdateSingleRecord(string tableName, JObject record, APIJSON_Role role = null)
  863. {
  864. role ??= _identitySvc.GetRole();
  865. if (!record.ContainsKey("id"))
  866. {
  867. throw Oops.Bah("未传主键id");
  868. }
  869. var dt = new Dictionary<string, object>();
  870. var sb = new StringBuilder(100);
  871. object id = null;
  872. foreach (var f in record)//遍历每个字段
  873. {
  874. if (f.Key.Equals("id", StringComparison.OrdinalIgnoreCase))
  875. {
  876. if (f.Value is JArray)//id数组
  877. {
  878. sb.Append($"{f.Key} in (@{f.Key})");
  879. id = FuncList.TransJArrayToSugarPara(f.Value);
  880. }
  881. else//单个id
  882. {
  883. sb.Append($"{f.Key}=@{f.Key}");
  884. id = FuncList.TransJObjectToSugarPara(f.Value);
  885. }
  886. }
  887. else if (IsCol(tableName, f.Key) && (role.Update.Column.Contains("*") || role.Update.Column.Contains(f.Key, StringComparer.CurrentCultureIgnoreCase)))
  888. {
  889. dt.Add(f.Key, FuncList.TransJObjectToSugarPara(f.Value));
  890. }
  891. }
  892. string whereSql = sb.ToString();
  893. int count = _db.Updateable(dt).AS(tableName).Where(whereSql, new { id }).ExecuteCommand();
  894. return count;
  895. }
  896. /// <summary>
  897. /// 更新单表,支持同表多条记录
  898. /// </summary>
  899. /// <param name="tableName"></param>
  900. /// <param name="records"></param>
  901. /// <param name="role"></param>
  902. /// <returns></returns>
  903. public int UpdateSingleTable(string tableName, JToken records, APIJSON_Role role = null)
  904. {
  905. role ??= _identitySvc.GetRole();
  906. int count = 0;
  907. if (records is JArray)//遍历每行记录
  908. {
  909. foreach (var record in records.ToObject<JObject[]>())
  910. {
  911. count += UpdateSingleRecord(tableName, record, role);
  912. }
  913. }
  914. else//单条记录
  915. {
  916. count = UpdateSingleRecord(tableName, records.ToObject<JObject>(), role);
  917. }
  918. return count;
  919. }
  920. }