SelectTable.cs 38 KB

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