DbSqlHelper.cs 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Data;
  4. using System.Data.Common;
  5. using System.Diagnostics;
  6. using System.Linq;
  7. using System.Reflection;
  8. using System.Text;
  9. namespace LJLib.DAL.SQL
  10. {
  11. /// <summary>
  12. /// 全局初始化时,需要添加要支持的引擎(SqlServer/Sqlite)
  13. /// </summary>
  14. internal static class DbSqlHelper
  15. {
  16. /// <summary>
  17. /// 从数据库获取当前时间
  18. /// SQL Server :SELECT GETDATE()
  19. /// SQLite :SELECT DATETIME()
  20. /// </summary>
  21. public static DateTime GetServerTime<TCommand>(TCommand cmd) where TCommand : DbCommand
  22. {
  23. var engine = GetEngine(cmd.GetType());
  24. return engine.GetServerTime(cmd);
  25. }
  26. /// <summary>
  27. /// 获取单表中符合条件的行数
  28. /// </summary>
  29. public static int SelectCount<TCommand>(TCommand cmd, string table, string wherestr, IDictionary<string, object> sqlparams = null) where TCommand : DbCommand
  30. {
  31. string strcmd = "SELECT COUNT(0) FROM " + table;
  32. if (!string.IsNullOrEmpty(wherestr))
  33. {
  34. wherestr = wherestr.Trim();
  35. strcmd += " WHERE " + wherestr;
  36. }
  37. cmd.CommandText = strcmd;
  38. cmd.CommandType = CommandType.Text;
  39. cmd.Parameters.Clear();
  40. if (sqlparams != null)
  41. {
  42. foreach (var sqlparam in sqlparams)
  43. {
  44. var value = sqlparam.Value;
  45. if (value == null)
  46. {
  47. value = DBNull.Value;
  48. }
  49. AddWithValue(cmd, sqlparam.Key, value);
  50. }
  51. }
  52. return Convert.ToInt32(cmd.ExecuteScalar());
  53. }
  54. /// <summary>
  55. /// 添加参数值
  56. /// </summary>
  57. private static void AddWithValue<TCommand>(TCommand cmd, string name, object value) where TCommand : DbCommand
  58. {
  59. var engine = GetEngine(cmd.GetType());
  60. engine.AddWithValue(cmd, name, value);
  61. if (cmd.Parameters[name].Value == null)
  62. {
  63. cmd.Parameters[name].Value = DBNull.Value;
  64. }
  65. }
  66. public static void SelectJoin<TCommand, T>(TCommand cmd, string selectStr, string whereStr, IDictionary<string, object> parms, string orderByStr, string outputFields, int pageindex, int pagesize, List<T> returnList)
  67. where TCommand : DbCommand
  68. where T : new()
  69. {
  70. cmd.CommandText = SqlStrHelper.BuildSelectStr(selectStr, ref outputFields, whereStr, orderByStr, pageindex, pagesize); ;
  71. cmd.CommandType = CommandType.Text;
  72. cmd.Parameters.Clear();
  73. if (parms != null)
  74. {
  75. foreach (var parm in parms)
  76. {
  77. AddWithValue(cmd, parm.Key, parm.Value);
  78. }
  79. }
  80. var properties = GetProperties(typeof(T), outputFields);
  81. GetValues(cmd, returnList, properties);
  82. }
  83. public static void SelectJoin<TCommand, T>(TCommand cmd, string selectStr, string whereStr, IDictionary<string, object> parms, string orderByStr, string outputFields, int pageindex, int pagesize, List<T> returnList, ref int totalcnt)
  84. where TCommand : DbCommand
  85. where T : new()
  86. {
  87. var parseResult = SqlStrHelper.ParseSelectStr(selectStr);
  88. if (parseResult.selectStr.ToUpper().Contains("DISTINCT"))
  89. {
  90. throw new NotImplementedException("不要过分依赖DISTINCT");
  91. }
  92. cmd.CommandText = SqlStrHelper.BuildSelectStr(parseResult, outputFields, whereStr, orderByStr, pageindex, pagesize);
  93. cmd.CommandType = CommandType.Text;
  94. cmd.Parameters.Clear();
  95. if (parms != null)
  96. {
  97. foreach (var parm in parms)
  98. {
  99. AddWithValue(cmd, parm.Key, parm.Value);
  100. }
  101. }
  102. var properties = GetProperties(typeof(T), outputFields);
  103. GetValues(cmd, returnList, properties);
  104. string strcmd = parseResult.selectStr + " COUNT(0) " + parseResult.fromStr;
  105. if (!string.IsNullOrEmpty(whereStr))
  106. {
  107. whereStr = whereStr.Trim();
  108. strcmd += " WHERE " + whereStr;
  109. }
  110. cmd.CommandText = strcmd;
  111. //cmd.CommandType = CommandType.Text;
  112. //cmd.Parameters.Clear();
  113. try
  114. {
  115. totalcnt = Convert.ToInt32(cmd.ExecuteScalar());
  116. }
  117. catch (Exception ex)
  118. {
  119. throw new Exception(string.Format("ex:{0}\r\ncmd:{1}", ex, cmd.CommandText));
  120. }
  121. }
  122. private static object ConvertValue(Type parmType, object value)
  123. {
  124. if (!parmType.IsAssignableFrom(value.GetType()))
  125. {
  126. if (parmType.IsAssignableFrom(typeof(byte)))
  127. {
  128. value = Convert.ToByte(value);
  129. }
  130. else if (parmType.IsAssignableFrom(typeof(sbyte)))
  131. {
  132. value = Convert.ToSByte(value);
  133. }
  134. else if (parmType.IsAssignableFrom(typeof(short)))
  135. {
  136. value = Convert.ToInt16(value);
  137. }
  138. else if (parmType.IsAssignableFrom(typeof(ushort)))
  139. {
  140. value = Convert.ToUInt16(value);
  141. }
  142. else if (parmType.IsAssignableFrom(typeof(int)))
  143. {
  144. value = Convert.ToInt32(value);
  145. }
  146. else if (parmType.IsAssignableFrom(typeof(uint)))
  147. {
  148. value = Convert.ToUInt32(value);
  149. }
  150. else if (parmType.IsAssignableFrom(typeof(long)))
  151. {
  152. value = Convert.ToInt64(value);
  153. }
  154. else if (parmType.IsAssignableFrom(typeof(ulong)))
  155. {
  156. value = Convert.ToUInt64(value);
  157. }
  158. else if (parmType.IsAssignableFrom(typeof(float)))
  159. {
  160. value = Convert.ToSingle(value);
  161. }
  162. else if (parmType.IsAssignableFrom(typeof(double)))
  163. {
  164. value = Convert.ToDouble(value);
  165. }
  166. else if (parmType.IsAssignableFrom(typeof(decimal)))
  167. {
  168. value = Convert.ToDecimal(value);
  169. }
  170. else if (parmType.IsAssignableFrom(typeof(bool)))
  171. {
  172. value = Convert.ToBoolean(value);
  173. }
  174. else if (parmType.IsAssignableFrom(typeof(bool)))
  175. {
  176. value = Convert.ToBoolean(value);
  177. }
  178. else if (parmType.IsAssignableFrom(typeof(char)))
  179. {
  180. value = Convert.ToChar(value);
  181. }
  182. else if (parmType.IsAssignableFrom(typeof(DateTime)))
  183. {
  184. value = Convert.ToDateTime(value);
  185. }
  186. else if (parmType.IsAssignableFrom(typeof(string)))
  187. {
  188. value = Convert.ToString(value);
  189. }
  190. else if (parmType.IsEnum)
  191. {
  192. value = Enum.ToObject(parmType, value);
  193. }
  194. else
  195. {
  196. throw new Exception(string.Format("不能将{0}转换成{1}", value.GetType(), parmType));
  197. }
  198. }
  199. return value;
  200. }
  201. public static int Select<TCommand, T>(TCommand cmd, string tablename, string whereStr, IDictionary<string, object> parms, string orderStr, int pagesize, int pageindex, IList<T> modles, IDictionary<string, string> maps, string fields)
  202. where TCommand : DbCommand
  203. where T : new()
  204. {
  205. var strCmd = string.Format("SELECT {0} FROM {1}", fields, tablename);
  206. cmd.CommandText = SqlStrHelper.BuildSelectStr(strCmd, ref fields, whereStr, orderStr, pageindex, pagesize);
  207. cmd.CommandType = CommandType.Text;
  208. cmd.Parameters.Clear();
  209. if (parms != null)
  210. {
  211. foreach (var parm in parms)
  212. {
  213. AddWithValue(cmd, parm.Key, parm.Value);
  214. }
  215. }
  216. var targetMaps = GetTargetMaps<T>(maps, fields);
  217. using (var reader = cmd.ExecuteReader())
  218. {
  219. while (reader.Read())
  220. {
  221. T modle = new T();
  222. GetValue(reader, modle, targetMaps);
  223. modles.Add(modle);
  224. }
  225. }
  226. return modles.Count;
  227. }
  228. private static void GetValue(DbDataReader reader, object modle, Dictionary<string, PropertyInfo> targetMaps)
  229. {
  230. foreach (var property in targetMaps)
  231. {
  232. MethodInfo setMethod = property.Value.GetSetMethod();
  233. if (setMethod == null)
  234. {
  235. continue;
  236. }
  237. object value = null;
  238. try
  239. {
  240. value = reader[property.Key];
  241. }
  242. catch (Exception)
  243. {
  244. continue;
  245. }
  246. if (value == null || value == DBNull.Value)
  247. {
  248. continue;
  249. }
  250. if (value is string)
  251. {
  252. value = value.ToString().Trim();
  253. }
  254. var parmType = setMethod.GetParameters()[0].ParameterType;
  255. value = ConvertValue(parmType, value);
  256. setMethod.Invoke(modle, new object[] { value });
  257. }
  258. }
  259. public static int Select<TCommand, T>(TCommand cmd, IList<T> modles, string wherestr, string fields = "*")
  260. where TCommand : DbCommand
  261. where T : new()
  262. {
  263. return Select(cmd, modles, wherestr, null, null, fields, 0, 0);
  264. }
  265. public static int Select<TCommand, T>(TCommand cmd, IList<T> modles, string wherestr, IDictionary<string, object> sqlparams, string fields = "*")
  266. where TCommand : DbCommand
  267. where T : new()
  268. {
  269. return Select(cmd, modles, wherestr, sqlparams, null, fields, 0, 0);
  270. }
  271. public static int Select<TCommand, T>(TCommand cmd, IList<T> modles, string wherestr, IDictionary<string, object> sqlparams, int pageindex, int pagesize, string orderstr, string fields = "*")
  272. where TCommand : DbCommand
  273. where T : new()
  274. {
  275. return Select(cmd, modles, wherestr, sqlparams, orderstr, fields, pageindex, pagesize);
  276. }
  277. public static int Select<TCommand, T>(TCommand cmd, IList<T> modles, string whereStr, IDictionary<string, object> sqlparams, string orderByStr, string outputFields, int pageindex, int pagesize)
  278. where TCommand : DbCommand
  279. where T : new()
  280. {
  281. if (modles.IsReadOnly)
  282. {
  283. throw new ArgumentException("参数modles不能为只读");
  284. }
  285. var propertyies = GetProperties(typeof(T), outputFields);
  286. if (propertyies.Count == 0)
  287. {
  288. propertyies = new List<PropertyInfo>(GetProperties(typeof(T)).Values);
  289. }
  290. var strCmd = string.Empty;
  291. foreach (var propertyInfo in propertyies)
  292. {
  293. if (string.IsNullOrEmpty(strCmd))
  294. {
  295. strCmd = propertyInfo.Name;
  296. }
  297. else
  298. {
  299. strCmd += "," + propertyInfo.Name;
  300. }
  301. }
  302. strCmd = "SELECT " + strCmd + " FROM " + typeof(T).Name;
  303. var outCmdStr = SqlStrHelper.BuildSelectStr(strCmd, ref outputFields, whereStr, orderByStr, pageindex, pagesize);
  304. cmd.CommandText = outCmdStr;
  305. cmd.CommandType = CommandType.Text;
  306. cmd.Parameters.Clear();
  307. if (sqlparams != null)
  308. {
  309. foreach (var parm in sqlparams)
  310. {
  311. AddWithValue(cmd, parm.Key, parm.Value);
  312. }
  313. }
  314. GetValues(cmd, modles, propertyies);
  315. return modles.Count;
  316. }
  317. private static void GetValues<TCommand, T>(TCommand cmd, IList<T> modles, IList<PropertyInfo> propertyies)
  318. where TCommand : DbCommand
  319. where T : new()
  320. {
  321. try
  322. {
  323. using (var reader = cmd.ExecuteReader())
  324. {
  325. while (reader.Read())
  326. {
  327. T modle = new T();
  328. GetValue(reader, modle, propertyies);
  329. modles.Add(modle);
  330. }
  331. }
  332. }
  333. catch (Exception)
  334. {
  335. //Debug.Write(cmd.CommandText);
  336. throw;
  337. }
  338. }
  339. private static void GetValue<T>(DbDataReader reader, T modle, IList<PropertyInfo> propertyies)
  340. {
  341. foreach (PropertyInfo property in propertyies)
  342. {
  343. MethodInfo setMethod = property.GetSetMethod();
  344. if (setMethod == null)
  345. {
  346. continue;
  347. }
  348. object value = null;
  349. try
  350. {
  351. value = reader[property.Name];
  352. }
  353. catch (Exception)
  354. {
  355. continue;
  356. }
  357. if (value == null || value == DBNull.Value)
  358. {
  359. continue;
  360. }
  361. if (value is string)
  362. {
  363. value = value.ToString().Trim();
  364. }
  365. var parmType = setMethod.GetParameters()[0].ParameterType;
  366. value = ConvertValue(parmType, value);
  367. setMethod.Invoke(modle, new object[] { value });
  368. }
  369. }
  370. private static object _pksyncRoot = new object();
  371. private static Dictionary<Type, string[]> _type_pks = new Dictionary<Type, string[]>();
  372. private static string[] GetPKs(Type type)
  373. {
  374. // DONE: 返回模型类的主键
  375. lock (_pksyncRoot)
  376. {
  377. if (_type_pks.ContainsKey(type))
  378. {
  379. return _type_pks[type];
  380. }
  381. var attrs = type.GetCustomAttributes(typeof(PK), true);
  382. if (attrs.Length == 0)
  383. {
  384. _type_pks[type] = new string[] { };
  385. }
  386. else
  387. {
  388. PK pk = attrs[0] as PK;
  389. _type_pks[type] = pk.keys;
  390. }
  391. return _type_pks[type];
  392. }
  393. }
  394. public static int SelectOne<TCommand, T>(TCommand cmd, string tablename, string whereStr, IDictionary<string, object> parms, T Modle, string fields) where TCommand : DbCommand
  395. {
  396. // 生成语句
  397. var propertyies = GetProperties(typeof(T), fields);
  398. if (propertyies.Count == 0)
  399. {
  400. propertyies = new List<PropertyInfo>(GetProperties(typeof(T)).Values);
  401. }
  402. var strCmd = string.Empty;
  403. foreach (var propertyInfo in propertyies)
  404. {
  405. if (string.IsNullOrEmpty(strCmd))
  406. {
  407. strCmd = propertyInfo.Name;
  408. }
  409. else
  410. {
  411. strCmd += "," + propertyInfo.Name;
  412. }
  413. }
  414. strCmd = "SELECT " + strCmd + " FROM " + tablename;
  415. if (!string.IsNullOrEmpty(whereStr))
  416. {
  417. strCmd += " WHERE " + whereStr;
  418. }
  419. cmd.CommandText = strCmd;
  420. cmd.CommandType = CommandType.Text;
  421. cmd.Parameters.Clear();
  422. if (parms != null)
  423. {
  424. foreach (var kvp in parms)
  425. {
  426. AddWithValue(cmd, kvp.Key, kvp.Value);
  427. }
  428. }
  429. using (var reader = cmd.ExecuteReader())
  430. {
  431. if (!reader.Read())
  432. {
  433. return 0;
  434. }
  435. GetValue(reader, Modle, propertyies);
  436. return 1;
  437. }
  438. }
  439. public static int SelectOne<TCommand, T>(TCommand cmd, T modle, string fields = "*") where TCommand : DbCommand
  440. {
  441. // 查找非空主键
  442. var fpkpropertyies = GetNotNullProperties(modle);
  443. // 生成语句
  444. var propertyies = GetProperties(typeof(T), fields);
  445. if (propertyies.Count == 0)
  446. {
  447. propertyies = new List<PropertyInfo>(GetProperties(typeof(T)).Values);
  448. }
  449. var strCmd = string.Empty;
  450. foreach (var propertyInfo in propertyies)
  451. {
  452. if (string.IsNullOrEmpty(strCmd))
  453. {
  454. strCmd = propertyInfo.Name;
  455. }
  456. else
  457. {
  458. strCmd += "," + propertyInfo.Name;
  459. }
  460. }
  461. strCmd = "SELECT " + strCmd + " FROM " + typeof(T).Name;
  462. strCmd += string.Format(" WHERE {0}=@{0}", fpkpropertyies[0].Name);
  463. for (int i = 1; i < fpkpropertyies.Count; i++)
  464. {
  465. strCmd += string.Format(" AND {0}=@{0}", fpkpropertyies[i].Name);
  466. }
  467. cmd.CommandText = strCmd;
  468. cmd.CommandType = CommandType.Text;
  469. cmd.Parameters.Clear();
  470. foreach (var property in fpkpropertyies)
  471. {
  472. object value = property.GetGetMethod().Invoke(modle, null);
  473. AddWithValue(cmd, "@" + property.Name, value);
  474. }
  475. using (var reader = cmd.ExecuteReader())
  476. {
  477. if (!reader.Read())
  478. {
  479. return 0;
  480. }
  481. GetValue(reader, modle, propertyies);
  482. return 1;
  483. }
  484. }
  485. /// <summary>
  486. /// 查找非空主键
  487. /// </summary>
  488. /// <typeparam name="T"></typeparam>
  489. /// <param name="modle"></param>
  490. /// <returns></returns>
  491. private static IList<PropertyInfo> GetNotNullProperties<T>(T modle)
  492. {
  493. var pks = GetPKs(typeof(T));
  494. if (pks == null || pks.Length == 0)
  495. {
  496. throw new Exception(string.Format("模型类{0}没有定义主键", typeof(T).FullName));
  497. }
  498. IList<PropertyInfo> fpkpropertyies = null;
  499. foreach (var pk in pks)
  500. {
  501. if (string.IsNullOrEmpty(pk))
  502. {
  503. throw new Exception(string.Format("模型类{0}的主键不能为空", typeof(T).FullName));
  504. }
  505. var withnullpk = false;
  506. var pkproperties = GetProperties(typeof(T), pk);
  507. if (pkproperties.Count == 0)
  508. {
  509. throw new Exception(string.Format("模型类{0}的主键与字段名不符", typeof(T).FullName));
  510. }
  511. foreach (var propertyInfo in pkproperties)
  512. {
  513. var getMethod = propertyInfo.GetGetMethod();
  514. var value = getMethod.Invoke(modle, null);
  515. if (value == null)
  516. {
  517. withnullpk = true;
  518. break;
  519. }
  520. }
  521. if (!withnullpk)
  522. {
  523. fpkpropertyies = pkproperties;
  524. break;
  525. }
  526. }
  527. if (fpkpropertyies == null)
  528. {
  529. throw new Exception("转入模型主键为空");
  530. }
  531. return fpkpropertyies;
  532. }
  533. public static int Delete<TCommand, T>(TCommand cmd, T modle) where TCommand : DbCommand
  534. {
  535. var fpkpropertyies = GetNotNullProperties(modle);
  536. var strCmd = string.Empty;
  537. strCmd = "DELETE FROM " + typeof(T).Name;
  538. strCmd += string.Format(" WHERE {0}=@{0}", fpkpropertyies[0].Name);
  539. for (int i = 1; i < fpkpropertyies.Count; i++)
  540. {
  541. strCmd += string.Format(" AND {0}=@{0}", fpkpropertyies[i].Name);
  542. }
  543. cmd.CommandText = strCmd;
  544. cmd.CommandType = CommandType.Text;
  545. cmd.Parameters.Clear();
  546. foreach (var property in fpkpropertyies)
  547. {
  548. object value = property.GetGetMethod().Invoke(modle, null);
  549. AddWithValue(cmd, "@" + property.Name, value);
  550. }
  551. return cmd.ExecuteNonQuery();
  552. }
  553. /// <summary>
  554. /// 异构对象插入数据库
  555. /// </summary>
  556. public static int Insert<TCommand, T>(TCommand cmd, string tablename, Dictionary<string, string> maps, T modle, string fields = "*") where TCommand : DbCommand
  557. {
  558. if (string.IsNullOrEmpty(tablename))
  559. {
  560. tablename = typeof(T).Name;
  561. }
  562. // DONE: 处理大小写问题
  563. var targetfields = GetTargetMaps<T>(maps, fields);
  564. cmd.CommandType = CommandType.Text;
  565. cmd.Parameters.Clear();
  566. string tablefields = string.Empty;
  567. string valuefields = string.Empty;
  568. foreach (var targetfield in targetfields)
  569. {
  570. if (string.IsNullOrEmpty(tablefields))
  571. {
  572. tablefields = targetfield.Key;
  573. valuefields = "@" + targetfield.Key;
  574. }
  575. else
  576. {
  577. tablefields += "," + targetfield.Key;
  578. valuefields += ",@" + targetfield.Key;
  579. }
  580. AddWithValue(cmd, "@" + targetfield.Key, targetfield.Value.GetGetMethod().Invoke(modle, null));
  581. }
  582. if (string.IsNullOrEmpty(tablefields))
  583. {
  584. throw new Exception("没有一个有效插入字段");
  585. }
  586. cmd.CommandText = string.Format("INSERT INTO {0}({1}) VALUES({2})", tablename, tablefields, valuefields);
  587. try
  588. {
  589. return cmd.ExecuteNonQuery();
  590. }
  591. catch (Exception ex)
  592. {
  593. Trace.Write(ex.ToString());
  594. Trace.Write(ModleToString(modle));
  595. throw;
  596. }
  597. }
  598. public static int Insert<TCommand, T>(TCommand cmd, T modle, string fields = "*") where TCommand : DbCommand
  599. {
  600. return Insert(cmd, null, null, modle, fields);
  601. }
  602. /// <summary>
  603. /// 批量插入数据到数据库
  604. /// </summary>
  605. /// <typeparam name="TCommand">数据库命令类型</typeparam>
  606. /// <typeparam name="T">数据模型类型</typeparam>
  607. /// <param name="cmd">数据库命令对象</param>
  608. /// <param name="models">要插入的数据列表</param>
  609. /// <param name="targetTable">目标表名</param>
  610. /// <param name="maps">字段映射字典,key为数据库字段名,value为模型属性名</param>
  611. /// <param name="fields">要插入的字段,默认为"*"</param>
  612. /// <returns>成功插入的记录数</returns>
  613. public static int BulkInsert<TCommand, T>(TCommand cmd, IList<T> models, string targetTable, Dictionary<string, string> maps = null, string fields = "*") where TCommand : DbCommand
  614. {
  615. if (models == null || models.Count == 0)
  616. {
  617. return 0;
  618. }
  619. var targetfields = GetTargetMaps<T>(maps, fields);
  620. if (targetfields.Count == 0)
  621. {
  622. throw new Exception("没有一个有效插入字段");
  623. }
  624. // 构建多值INSERT SQL语句
  625. string fieldList = string.Join(", ", targetfields.Keys);
  626. var valueClauses = new List<string>();
  627. var parameters = new Dictionary<string, object>();
  628. // 为每条数据创建VALUES子句
  629. for (int i = 0; i < models.Count; i++)
  630. {
  631. var model = models[i];
  632. var paramNames = new List<string>();
  633. foreach (var field in targetfields)
  634. {
  635. string paramName = $"@p{i}_{field.Key}";
  636. var propertyValue = field.Value.GetGetMethod().Invoke(model, null);
  637. parameters[paramName] = propertyValue ?? DBNull.Value;
  638. paramNames.Add(paramName);
  639. }
  640. valueClauses.Add($"({string.Join(", ", paramNames)})");
  641. }
  642. // 构建完整的INSERT语句
  643. cmd.CommandText = $"INSERT INTO {targetTable}({fieldList}) VALUES {string.Join(", ", valueClauses)}";
  644. cmd.CommandType = CommandType.Text;
  645. cmd.Parameters.Clear();
  646. // 添加所有参数
  647. foreach (var param in parameters)
  648. {
  649. AddWithValue(cmd, param.Key, param.Value);
  650. }
  651. try
  652. {
  653. return cmd.ExecuteNonQuery();
  654. }
  655. catch (Exception ex)
  656. {
  657. Trace.Write($"BulkInsert Error: {ex.Message}");
  658. Trace.Write($"SQL: {cmd.CommandText}");
  659. Trace.Write($"Models Count: {models.Count}");
  660. throw;
  661. }
  662. }
  663. private static Dictionary<string, PropertyInfo> GetTargetMaps<T>(IDictionary<string, string> maps, string fields)
  664. {
  665. var newmaps = new Dictionary<string, string>();
  666. if (maps != null)
  667. {
  668. foreach (var map in maps)
  669. {
  670. newmaps[map.Key.Trim().ToLower()] = map.Value.Trim().ToLower();
  671. }
  672. }
  673. var targetfields = new Dictionary<string, PropertyInfo>();
  674. var orgfields = GetProperties(typeof (T));
  675. string[] arr_fields;
  676. if (fields.Equals("*"))
  677. {
  678. arr_fields = orgfields.Keys.ToArray();
  679. }
  680. else
  681. {
  682. arr_fields = fields.Split(',');
  683. }
  684. foreach (var field in arr_fields)
  685. {
  686. var key = field.Trim().ToLower();
  687. if (targetfields.ContainsKey(key))
  688. {
  689. continue;
  690. }
  691. if (newmaps.ContainsKey(key) && orgfields.ContainsKey(newmaps[key]))
  692. {
  693. targetfields[key] = orgfields[newmaps[key]];
  694. }
  695. else if (orgfields.ContainsKey(key))
  696. {
  697. targetfields[key] = orgfields[key];
  698. }
  699. }
  700. return targetfields;
  701. }
  702. public static int Update<TCommand, T>(TCommand cmd, string tablename, Dictionary<string, string> maps, T modle, string pkfields, string fields = "*") where TCommand : DbCommand
  703. {
  704. // DONE: 处理大小写问题
  705. var pkfields_dir = GetTargetMaps<T>(maps, pkfields);
  706. var targetfields = GetTargetMaps<T>(maps, fields);
  707. cmd.CommandType = CommandType.Text;
  708. cmd.Parameters.Clear();
  709. string keyFields = string.Empty;
  710. foreach (var targetfield in pkfields_dir)
  711. {
  712. if (string.IsNullOrEmpty(keyFields))
  713. {
  714. keyFields = string.Format("{0} = @{0}", targetfield.Key);
  715. }
  716. else
  717. {
  718. keyFields += string.Format(" AND {0} = @{0}", targetfield.Key);
  719. }
  720. AddWithValue(cmd, "@" + targetfield.Key, targetfield.Value.GetGetMethod().Invoke(modle, null));
  721. }
  722. if (string.IsNullOrEmpty(keyFields))
  723. {
  724. throw new Exception("没有一个有效的条件字段");
  725. }
  726. string setFields = string.Empty;
  727. foreach (var targetfield in targetfields)
  728. {
  729. if (string.IsNullOrEmpty(setFields))
  730. {
  731. setFields = string.Format("{0} = @{0}", targetfield.Key);
  732. }
  733. else
  734. {
  735. setFields += string.Format(", {0} = @{0}", targetfield.Key);
  736. }
  737. AddWithValue(cmd, "@" + targetfield.Key, targetfield.Value.GetGetMethod().Invoke(modle, null));
  738. }
  739. if (string.IsNullOrEmpty(setFields))
  740. {
  741. throw new Exception("没有一个有效更新字段");
  742. }
  743. cmd.CommandText = string.Format("UPDATE {0} SET {1} WHERE {2}", tablename, setFields, keyFields);
  744. try
  745. {
  746. return cmd.ExecuteNonQuery();
  747. }
  748. catch (Exception ex)
  749. {
  750. Trace.Write(ex.ToString());
  751. Trace.Write(ModleToString(modle));
  752. throw;
  753. }
  754. }
  755. public static int Update<TCommand, T>(TCommand cmd, T modle, string fields = "*") where TCommand : DbCommand
  756. {
  757. var pks = GetPKs(typeof(T));
  758. if (pks == null || pks.Length == 0)
  759. {
  760. throw new Exception(string.Format("当前类{0}没有定义关键字段", typeof(T).Name));
  761. }
  762. var pkfields = pks[0];
  763. if (pks.Length > 0)
  764. {
  765. foreach (var pk in pks)
  766. {
  767. if (string.IsNullOrEmpty(pk))
  768. {
  769. throw new Exception(string.Format("模型类{0}的主键不能为空", typeof(T).FullName));
  770. }
  771. var withnullpk = false;
  772. var pkproperties = GetProperties(typeof(T), pk);
  773. if (pkproperties.Count == 0)
  774. {
  775. throw new Exception(string.Format("模型类{0}的主键与字段名不符", typeof(T).FullName));
  776. }
  777. foreach (var propertyInfo in pkproperties)
  778. {
  779. var getMethod = propertyInfo.GetGetMethod();
  780. var value = getMethod.Invoke(modle, null);
  781. if (value == null)
  782. {
  783. withnullpk = true;
  784. break;
  785. }
  786. }
  787. if (!withnullpk)
  788. {
  789. pkfields = pk;
  790. break;
  791. }
  792. }
  793. }
  794. return Update(cmd, typeof (T).Name, null, modle, pkfields, fields);
  795. }
  796. public static int InsertOrUpdate<TCommand, T>(TCommand cmd, T modle, string fields = "*") where TCommand : DbCommand
  797. {
  798. try
  799. {
  800. // 查找非空主键
  801. var ifinsert = false;
  802. var pks = GetPKs(typeof(T));
  803. if (pks == null || pks.Length == 0)
  804. {
  805. ifinsert = true;
  806. }
  807. IList<PropertyInfo> fpkpropertyies = null;
  808. if (!ifinsert)
  809. {
  810. foreach (var pk in pks)
  811. {
  812. if (string.IsNullOrEmpty(pk))
  813. {
  814. throw new Exception(string.Format("模型类{0}的主键不能为空", typeof(T).FullName));
  815. }
  816. var withnullpk = false;
  817. var pkproperties = GetProperties(typeof(T), pk);
  818. if (pkproperties.Count == 0)
  819. {
  820. throw new Exception(string.Format("模型类{0}的主键与字段名不符", typeof(T).FullName));
  821. }
  822. foreach (var propertyInfo in pkproperties)
  823. {
  824. var getMethod = propertyInfo.GetGetMethod();
  825. var value = getMethod.Invoke(modle, null);
  826. if (value == null)
  827. {
  828. withnullpk = true;
  829. break;
  830. }
  831. }
  832. if (!withnullpk)
  833. {
  834. fpkpropertyies = pkproperties;
  835. break;
  836. }
  837. }
  838. if (fpkpropertyies == null)
  839. {
  840. ifinsert = true;
  841. }
  842. }
  843. List<PropertyInfo> propertyies = null;
  844. if (!ifinsert)
  845. {
  846. // 按主键更新
  847. propertyies = GetProperties(typeof(T), fields);
  848. if (propertyies.Count == 0)
  849. {
  850. propertyies = new List<PropertyInfo>(GetProperties(typeof(T)).Values);
  851. }
  852. var pknames = new HashSet<string>();
  853. foreach (var fpk in fpkpropertyies)
  854. {
  855. pknames.Add(fpk.Name);
  856. }
  857. for (int i = propertyies.Count - 1; i >= 0; i--)
  858. {
  859. if (pknames.Contains(propertyies[i].Name))
  860. {
  861. propertyies.RemoveAt(i);
  862. }
  863. }
  864. if (propertyies.Count == 0)
  865. {
  866. string strCmd = string.Format("SELECT COUNT(0) FROM " + typeof(T).Name + " WHERE {0}=@{0}", fpkpropertyies[0].Name);
  867. for (int i = 1; i < fpkpropertyies.Count; i++)
  868. {
  869. strCmd += string.Format(" AND {0}=@{0}", fpkpropertyies[i].Name);
  870. }
  871. cmd.CommandText = strCmd;
  872. cmd.CommandType = CommandType.Text;
  873. cmd.Parameters.Clear();
  874. foreach (var pk in fpkpropertyies)
  875. {
  876. object value = pk.GetGetMethod().Invoke(modle, null);
  877. AddWithValue(cmd, "@" + pk.Name, value);
  878. }
  879. var cnt = Convert.ToUInt32(cmd.ExecuteScalar());
  880. if (cnt == 0)
  881. {
  882. ifinsert = true;
  883. }
  884. }
  885. else
  886. {
  887. string strCmd = string.Format("UPDATE " + typeof(T).Name + " SET {0}=@{0}", propertyies[0].Name);
  888. for (int i = 1; i < propertyies.Count; i++)
  889. {
  890. strCmd += string.Format(",{0}=@{0}", propertyies[i].Name);
  891. }
  892. strCmd += string.Format(" WHERE {0}=@{0}", fpkpropertyies[0].Name);
  893. for (int i = 1; i < fpkpropertyies.Count; i++)
  894. {
  895. strCmd += string.Format(" AND {0}=@{0}", fpkpropertyies[i].Name);
  896. }
  897. cmd.CommandText = strCmd;
  898. cmd.CommandType = CommandType.Text;
  899. cmd.Parameters.Clear();
  900. foreach (var pk in fpkpropertyies)
  901. {
  902. object value = pk.GetGetMethod().Invoke(modle, null);
  903. AddWithValue(cmd, "@" + pk.Name, value);
  904. }
  905. foreach (var field in propertyies)
  906. {
  907. object value = field.GetGetMethod().Invoke(modle, null);
  908. AddWithValue(cmd, "@" + field.Name, value);
  909. }
  910. var cnt = cmd.ExecuteNonQuery();
  911. if (cnt == 0)
  912. {
  913. ifinsert = true;
  914. }
  915. else
  916. {
  917. return cnt;
  918. }
  919. }
  920. }
  921. if (ifinsert)
  922. {
  923. // 插入
  924. if (propertyies == null) // 只有在无主键的情况下才会为空
  925. {
  926. propertyies = GetProperties(typeof(T), fields);
  927. if (propertyies.Count == 0)
  928. {
  929. propertyies = new List<PropertyInfo>(GetProperties(typeof(T)).Values);
  930. }
  931. }
  932. if (fpkpropertyies != null)
  933. {
  934. propertyies.AddRange(fpkpropertyies);
  935. }
  936. if (propertyies.Count == 0)
  937. {
  938. throw new Exception(string.Format("模型{0}没有字段定义", typeof(T).FullName));
  939. }
  940. string strCmd = string.Format("INSERT INTO " + typeof(T).Name + "({0}", propertyies[0].Name);
  941. for (int i = 1; i < propertyies.Count; i++)
  942. {
  943. strCmd += string.Format(",{0}", propertyies[i].Name);
  944. }
  945. strCmd += string.Format(") VALUES(@{0}", propertyies[0].Name);
  946. for (int i = 1; i < propertyies.Count; i++)
  947. {
  948. strCmd += string.Format(",@{0}", propertyies[i].Name);
  949. }
  950. strCmd += ")";
  951. cmd.CommandText = strCmd;
  952. cmd.CommandType = CommandType.Text;
  953. cmd.Parameters.Clear();
  954. foreach (var field in propertyies)
  955. {
  956. object value = field.GetGetMethod().Invoke(modle, null);
  957. AddWithValue(cmd, "@" + field.Name, value);
  958. }
  959. return cmd.ExecuteNonQuery();
  960. }
  961. return 0;
  962. }
  963. catch (Exception ex)
  964. {
  965. Trace.Write(ex.ToString());
  966. Trace.Write(ModleToString(modle));
  967. throw;
  968. }
  969. }
  970. private static object ModleToString(object modle)
  971. {
  972. if (modle == null)
  973. {
  974. return "{}";
  975. }
  976. var list = GetProperties(modle.GetType()).Values;
  977. StringBuilder rslt = new StringBuilder();
  978. rslt.Append(modle.GetType().ToString() + ":{");
  979. bool hasone = false;
  980. foreach (var pro in list)
  981. {
  982. var getMethod = pro.GetGetMethod();
  983. if (getMethod == null)
  984. {
  985. continue;
  986. }
  987. var value = getMethod.Invoke(modle, null);
  988. var curent = string.Format("{0}:\"{1}\"", pro.Name, value ?? "nil");
  989. if (!hasone)
  990. {
  991. rslt.Append(curent);
  992. hasone = true;
  993. }
  994. else
  995. {
  996. rslt.Append("," + curent);
  997. }
  998. }
  999. rslt.Append("}");
  1000. return rslt.ToString();
  1001. }
  1002. private static List<PropertyInfo> GetProperties(Type type, string outputFields)
  1003. {
  1004. List<PropertyInfo> rslt = new List<PropertyInfo>();
  1005. Dictionary<string, PropertyInfo> properties = GetProperties(type);
  1006. string[] fields = outputFields.Split(',');
  1007. foreach (string field in fields)
  1008. {
  1009. string key = field.Trim().ToLower();
  1010. if (properties.ContainsKey(key))
  1011. {
  1012. rslt.Add(properties[key]);
  1013. }
  1014. }
  1015. return rslt;
  1016. }
  1017. private static Dictionary<Type, Dictionary<string, PropertyInfo>> _typeinfoCache = new Dictionary<Type, Dictionary<string, PropertyInfo>>();
  1018. private static object _syncRoot_typeinfoCache = new object();
  1019. private static Dictionary<string, PropertyInfo> GetProperties(Type type)
  1020. {
  1021. lock (_syncRoot_typeinfoCache)
  1022. {
  1023. if (_typeinfoCache.ContainsKey(type))
  1024. {
  1025. return _typeinfoCache[type];
  1026. }
  1027. PropertyInfo[] properties = type.GetProperties();
  1028. Dictionary<string, PropertyInfo> dirProperties = new Dictionary<string, PropertyInfo>();
  1029. foreach (PropertyInfo property in properties)
  1030. {
  1031. string key = property.Name.Trim().ToLower();
  1032. if (!dirProperties.ContainsKey(key))
  1033. {
  1034. dirProperties[key] = property;
  1035. }
  1036. }
  1037. _typeinfoCache[type] = dirProperties;
  1038. return dirProperties;
  1039. }
  1040. }
  1041. private static Dictionary<Type, ISqlEngine> _cmd_engines = new Dictionary<Type, ISqlEngine>();
  1042. private static object _eng_root = new object();
  1043. public static void Add<T>(SqlEngine<T> engine) where T : DbCommand
  1044. {
  1045. if (engine == null)
  1046. {
  1047. throw new Exception("engine参数不能为null");
  1048. }
  1049. lock (_eng_root)
  1050. {
  1051. _cmd_engines[typeof(T)] = engine;
  1052. }
  1053. }
  1054. private static ISqlEngine GetEngine(Type type)
  1055. {
  1056. lock (_eng_root)
  1057. {
  1058. if (!_cmd_engines.ContainsKey(type))
  1059. {
  1060. throw new Exception(string.Format("{0}未关联数据库引擎", type.FullName));
  1061. }
  1062. return _cmd_engines[type];
  1063. }
  1064. }
  1065. }
  1066. }