DbSqlHelper.cs 38 KB

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