SqlMapperExtensions.cs 86 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel.DataAnnotations;
  4. using System.Data;
  5. using System.Diagnostics;
  6. using System.Linq;
  7. using System.Reflection;
  8. using System.Text;
  9. using System.Collections.Concurrent;
  10. using System.Reflection.Emit;
  11. using System.Threading;
  12. using System.Runtime.CompilerServices;
  13. using System.Linq.Expressions;
  14. using System.Data.SqlClient;
  15. using System.Configuration;
  16. using XYY.Core.Standard.Data.Infrastructure;
  17. using XYY.Common.Standard;
  18. using XYY.Common.Standard.Attributes;
  19. using KeyAttribute = System.ComponentModel.DataAnnotations.KeyAttribute;
  20. using XYY.Core;
  21. using System.Threading.Tasks;
  22. namespace Dapper
  23. {
  24. public static class SqlMapperExtensions
  25. {
  26. public enum Operate
  27. {
  28. //等于
  29. _Eq_,
  30. /// <summary>
  31. /// 日期等于
  32. /// </summary>
  33. _DataEq_,
  34. //不等于
  35. _NotEq_,
  36. //任意匹配
  37. _Co_,
  38. //小于
  39. _Le_,
  40. //大于
  41. _Gr_,
  42. //小于等于
  43. _LeE_,
  44. //大于等于
  45. _GrE_,
  46. //IN
  47. _In_,
  48. //NOT IN
  49. _NotIn_,
  50. _IsNlNumGr_,
  51. _IsNlNumLe_,
  52. _IsNotNl_,
  53. _IsNl_
  54. }
  55. public interface IProxy
  56. {
  57. bool IsDirty { get; set; }
  58. }
  59. private static readonly ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>> KeyProperties = new ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>>();
  60. private static readonly ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>> TypeProperties = new ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>>();
  61. private static readonly ConcurrentDictionary<RuntimeTypeHandle, string> GetQueries = new ConcurrentDictionary<RuntimeTypeHandle, string>();
  62. private static readonly ConcurrentDictionary<RuntimeTypeHandle, string> TypeTableName = new ConcurrentDictionary<RuntimeTypeHandle, string>();
  63. private static readonly ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>> ComputedProperties = new ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>>();
  64. private static IEnumerable<PropertyInfo> KeyPropertiesCache(Type type)
  65. {
  66. if (KeyProperties.ContainsKey(type.TypeHandle))
  67. {
  68. return KeyProperties[type.TypeHandle];
  69. }
  70. var allProperties = TypePropertiesCache(type);
  71. var keyProperties = allProperties.Where(p => p.GetCustomAttributes(true).Any(a => a is KeyAttribute)).ToList();
  72. if (keyProperties.Count == 0)
  73. {
  74. var idProp = allProperties.Where(p => p.Name.ToLower() == "id").FirstOrDefault();
  75. if (idProp != null)
  76. {
  77. keyProperties.Add(idProp);
  78. }
  79. }
  80. KeyProperties[type.TypeHandle] = keyProperties;
  81. return keyProperties;
  82. }
  83. private static IEnumerable<PropertyInfo> ComputedPropertiesCache(Type type)
  84. {
  85. if (ComputedProperties.ContainsKey(type.TypeHandle))
  86. {
  87. return ComputedProperties[type.TypeHandle];
  88. }
  89. var allProperties = TypePropertiesCache(type);
  90. var computedProperties = allProperties.Where(p => p.GetCustomAttributes(true).Any(a => a is NoDbAttribute)).ToList();
  91. ComputedProperties[type.TypeHandle] = computedProperties;
  92. return computedProperties;
  93. }
  94. private static IEnumerable<PropertyInfo> TypePropertiesCache(Type type)
  95. {
  96. if (TypeProperties.ContainsKey(type.TypeHandle))
  97. {
  98. return TypeProperties[type.TypeHandle];
  99. }
  100. var properties = type.GetProperties();
  101. TypeProperties[type.TypeHandle] = properties;
  102. return properties;
  103. }
  104. /// <summary>
  105. /// Returns a single entity by a single id from table "Ts". T must be of interface type.
  106. /// Id must be marked with [Key] attribute.
  107. /// Created entity is tracked/intercepted for changes and used by the Update() extension.
  108. /// </summary>
  109. /// <typeparam name="T">Interface type to create and populate</typeparam>
  110. /// <param name="connection">Open SqlConnection</param>
  111. /// <param name="id">Id of the entity to get, must be marked with [Key] attribute</param>
  112. /// <returns>Entity of T</returns>
  113. public static async Task<T> GetAsync<T>(this IUnitOfWork unitOfWork, dynamic id, int? commandTimeout = null) where T : class
  114. {
  115. var type = typeof(T);
  116. string sql;
  117. //if (!GetQueries.TryGetValue(type.TypeHandle, out sql))
  118. //{
  119. var keys = KeyPropertiesCache(type);
  120. if (keys.Count() > 1)
  121. throw new DataException("Get<T> only supports an entity with a single [Key] property");
  122. if (keys.Count() == 0)
  123. throw new DataException("Get<T> only supports en entity with a [Key] property");
  124. var onlyKey = keys.First();
  125. var name = GetTableName(type);
  126. // TODO: pluralizer
  127. // TODO: query information schema and only select fields that are both in information schema and underlying class / interface
  128. sql = "select * from " + name + "(nolock) where " + onlyKey.Name + " = @id";
  129. // GetQueries[type.TypeHandle] = sql;
  130. //}
  131. #if DEBUG
  132. Trace.WriteLine(sql);
  133. #endif
  134. var dynParms = new DynamicParameters();
  135. dynParms.Add("@id", id);
  136. T obj = null;
  137. if (type.IsInterface)
  138. {
  139. var r = await unitOfWork.Connection.QueryAsync(sql, dynParms);
  140. var res = r.FirstOrDefault() as IDictionary<string, object>;
  141. if (res == null)
  142. return (T)((object)null);
  143. obj = ProxyGenerator.GetInterfaceProxy<T>();
  144. foreach (var property in TypePropertiesCache(type))
  145. {
  146. var val = res[property.Name];
  147. property.SetValue(obj, val, null);
  148. }
  149. ((IProxy)obj).IsDirty = false; //reset change tracking and return
  150. }
  151. else
  152. {
  153. var r = await unitOfWork.Connection.QueryAsync<T>(sql, dynParms, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout);
  154. obj = r.FirstOrDefault();
  155. }
  156. return obj;
  157. }
  158. private static string TranslateWhere(List<QueryParamer> paramer)
  159. {
  160. string where = "";
  161. foreach (var item in paramer)
  162. {
  163. Operate operate = (Operate)Enum.Parse(typeof(Operate), string.Format("{0}{1}{0}", "_", item.Method));
  164. switch (operate)
  165. {
  166. case Operate._Eq_:
  167. where += string.Format(" AND {0} = N'{1}' ", item.Filed.Replace("$$", "."), item.Value);
  168. break;
  169. case Operate._DataEq_:
  170. where += string.Format(" AND CONVERT(VARCHAR(8),{0},112) = '{1}' ", item.Filed, item.Value.Replace("-", ""));
  171. break;
  172. case Operate._NotEq_:
  173. where += string.Format(" AND {0} != N'{1}' ", item.Filed, item.Value);
  174. break;
  175. case Operate._Co_:
  176. where += string.Format(" AND {0} like '%{1}%' ", item.Filed, item.Value);
  177. break;
  178. case Operate._Le_:
  179. if (item.Value.IsMatch("^(-?[0-9]*[.]*[0-9]{0,3})$"))
  180. {
  181. where += string.Format(" AND {0} < {1} ", item.Filed, item.Value);
  182. }
  183. else
  184. {
  185. where += string.Format(" AND {0} < '{1}' ", item.Filed, item.Value);
  186. }
  187. break;
  188. case Operate._Gr_:
  189. if (item.Value.IsMatch("^(-?[0-9]*[.]*[0-9]{0,3})$"))
  190. {
  191. where += string.Format(" AND {0} > {1} ", item.Filed, item.Value);
  192. }
  193. else
  194. {
  195. where += string.Format(" AND {0} > '{1}' ", item.Filed, item.Value);
  196. }
  197. break;
  198. case Operate._LeE_:
  199. if (item.Value.IsMatch("^(-?[0-9]*[.]*[0-9]{0,3})$"))
  200. {
  201. where += string.Format(" AND {0} <= {1} ", item.Filed, item.Value);
  202. }
  203. if (item.Value.IsMatch("\\d{4}-\\d{2}-\\d{2}"))
  204. {
  205. where += string.Format(" AND {0} <= '{1} 23:59:59.999'", item.Filed, item.Value);
  206. }
  207. else
  208. {
  209. where += string.Format(" AND {0} <= '{1}' ", item.Filed, item.Value);
  210. }
  211. break;
  212. case Operate._GrE_:
  213. if (item.Value.IsMatch("^(-?[0-9]*[.]*[0-9]{0,3})$"))
  214. {
  215. where += string.Format(" AND {0} >= {1} ", item.Filed, item.Value);
  216. }
  217. if (item.Value.IsMatch("\\d{4}-\\d{2}-\\d{2}"))
  218. {
  219. where += string.Format(" AND {0} >= '{1} 00:00:00.000'", item.Filed, item.Value);
  220. }
  221. else
  222. {
  223. where += string.Format(" AND {0} >= '{1}' ", item.Filed, item.Value);
  224. }
  225. break;
  226. case Operate._In_:
  227. if (item.Value.IsMatch("^\\d$"))
  228. {
  229. where += string.Format(" AND {0} in ( {1} )", item.Filed, item.Value);
  230. }
  231. else
  232. {
  233. if (item.Value.IndexOf(',') > -1)
  234. {
  235. string value = item.Value.Trim(',');
  236. if (value != string.Empty)
  237. {
  238. where += string.Format(" AND {0} in ( '{1}' )", item.Filed, value.Replace(",", "','"));
  239. }
  240. }
  241. else if (item.Value.IndexOf('\n') > -1)
  242. {
  243. string value = item.Value.Trim('\n');
  244. if (value != string.Empty)
  245. {
  246. where += string.Format(" AND {0} in ( '{1}' )", item.Filed, value.Replace("\n", "','"));
  247. }
  248. }
  249. else
  250. {
  251. if (item.Value != string.Empty)
  252. {
  253. where += string.Format(" AND {0} in ( '{1}' )", item.Filed, item.Value);
  254. }
  255. }
  256. }
  257. break;
  258. case Operate._NotIn_:
  259. where += string.Format(" AND {0} not in ( {1} )", item.Filed, item.Value);
  260. break;
  261. case Operate._IsNlNumGr_:
  262. where += string.Format(" AND isnull({0},0) >= {1} ", item.Filed, item.Value);
  263. break;
  264. case Operate._IsNlNumLe_:
  265. where += string.Format(" AND isnull({0},0) <= {1} ", item.Filed, item.Value);
  266. break;
  267. case Operate._IsNotNl_:
  268. where += string.Format(" AND isnull({0},'') != '{1}' ", item.Filed, item.Value);
  269. break;
  270. case Operate._IsNl_:
  271. where += string.Format(" AND isnull({0},'') = '{1}' ", item.Filed, item.Value);
  272. break;
  273. }
  274. }
  275. return where;
  276. }
  277. public static string GetWhere(this IUnitOfWork unitOfWork, List<QueryParamer> paramer)
  278. {
  279. return TranslateWhere(paramer);
  280. }
  281. /// <summary>
  282. /// 查询分页数据(优化)
  283. /// 该方法必须包含主键
  284. /// </summary>
  285. /// <typeparam name="T"></typeparam>
  286. /// <param name="unitOfWork"></param>
  287. /// <param name="queryModel"></param>
  288. /// <param name="commandTimeount"></param>
  289. /// <returns></returns>
  290. public static async Task<PageResult<T>> GetPagingList2Async<T>(this IUnitOfWork unitOfWork, QueryModel queryModel, int? commandTimeount = null) where T : class
  291. {
  292. var type = typeof(T);
  293. string sql;
  294. string tableName = GetTableName(type);
  295. sql = @"select * from ( select Row_Number()over(order by {0})rowId,{4} from " + tableName + @"(nolock) {1})T
  296. join " + tableName + @" b on t.{4} = b.{4} where rowId between {2} and {3};
  297. select count(0) from " + tableName + @"(nolock) {1}";
  298. if (string.IsNullOrEmpty(queryModel.Key))
  299. queryModel.Key = "Id";
  300. //sql = @"select * from ( select Row_Number()over(order by {0})rowId, * from " + tableName + @"(nolock) {1} )T where rowId between {2} and {3};
  301. // select count(0) from " + tableName + @"(nolock) {1}";
  302. string whereString = "WHERE 1=1 ";
  303. string sortString = "";
  304. //Where
  305. if (queryModel.QueryParamer != null && queryModel.QueryParamer.Count > 0)
  306. {
  307. var where = TranslateWhere(queryModel.QueryParamer);
  308. if (!string.IsNullOrWhiteSpace(where))
  309. {
  310. whereString += where;
  311. }
  312. }
  313. if (queryModel.DataPermission != null && queryModel.DataPermission.Count > 0)
  314. {//存在数据权限
  315. var allProperties = TypePropertiesCache(type);
  316. for (var i = 0; i < allProperties.Count(); i++)
  317. {
  318. var property = allProperties.ElementAt(i);
  319. var identity = property.GetCustomAttribute<DataPermissionAttribute>();
  320. if (identity == null)
  321. continue;
  322. var permission = queryModel.DataPermission.Find(x => x.PermissioinType == identity.PermissionType.GetValue());
  323. if (permission == null)
  324. continue;
  325. if (string.IsNullOrWhiteSpace(permission.Value))
  326. continue;
  327. whereString += " AND {0} IN ({1})".Formater(property.Name, permission.Value.TrimEnd(','));
  328. }
  329. }
  330. //if (expression != null)
  331. //{
  332. // var translator = new QueryTranslator();
  333. // whereString = " where " + translator.Translate(expression);
  334. //}
  335. //Sort
  336. if (queryModel.QuerySort == null || queryModel.QuerySort.Count == 0)
  337. {
  338. var keys = KeyPropertiesCache(type);
  339. if (keys.Count() == 0)
  340. throw new DataException("查询对象中必须包含主键");
  341. sortString = keys.First().Name;
  342. }
  343. else
  344. {
  345. foreach (var item in queryModel.QuerySort)
  346. {
  347. sortString += " " + item.Field + " " + (item.IsDesc ? "DESC" : "") + ",";
  348. }
  349. sortString = sortString.TrimEnd(',');
  350. }
  351. sql = string.Format(sql, sortString, whereString, (queryModel.PageIndex - 1) * queryModel.PageSize + 1, queryModel.PageSize * queryModel.PageIndex, queryModel.Key);
  352. var grid = await unitOfWork.Connection.QueryMultipleAsync(sql, transaction: unitOfWork.Transaction, commandTimeout: commandTimeount);
  353. #if DEBUG
  354. Trace.WriteLine(sql);
  355. #endif
  356. return new PageResult<T>()
  357. {
  358. Result = grid.Read<T>(),
  359. TotalCount = grid.Read<int>().SingleOrDefault(),
  360. PageIndex = queryModel.PageIndex,
  361. PageSize = queryModel.PageIndex
  362. };
  363. }
  364. public static async Task<PageResult<T>> GetPagingListAsync<T>(this IUnitOfWork unitOfWork, QueryModel queryModel, int? commandTimeout = null) where T : class
  365. {
  366. var type = typeof(T);
  367. string sql;
  368. string tableName = GetTableName(type);
  369. sql = @"select * from ( select Row_Number()over(order by {0})rowId, * from " + tableName + @"(nolock) {1} )T where rowId between {2} and {3};
  370. select count(0) from " + tableName + @"(nolock) {1}";
  371. string whereString = "WHERE 1=1 ";
  372. string sortString = "";
  373. //Where
  374. if (queryModel != null && queryModel.QueryParamer != null && queryModel.QueryParamer.Count > 0)
  375. {
  376. var where = TranslateWhere(queryModel.QueryParamer);
  377. if (!string.IsNullOrWhiteSpace(where))
  378. {
  379. whereString += where;
  380. }
  381. }
  382. if (queryModel.DataPermission != null && queryModel.DataPermission.Count > 0)
  383. {//存在数据权限
  384. var allProperties = TypePropertiesCache(type);
  385. for (var i = 0; i < allProperties.Count(); i++)
  386. {
  387. var property = allProperties.ElementAt(i);
  388. var identity = property.GetCustomAttribute<DataPermissionAttribute>();
  389. if (identity == null)
  390. continue;
  391. var permission = queryModel.DataPermission.Find(x => x.PermissioinType == identity.PermissionType.GetValue());
  392. if (permission == null)
  393. continue;
  394. if (string.IsNullOrWhiteSpace(permission.Value))
  395. continue;
  396. whereString += " AND {0} IN ({1})".Formater(property.Name, permission.Value.TrimEnd(','));
  397. }
  398. }
  399. //if (expression != null)
  400. //{
  401. // var translator = new QueryTranslator();
  402. // whereString = " where " + translator.Translate(expression);
  403. //}
  404. //Sort
  405. if (queryModel.QuerySort == null || queryModel.QuerySort.Count == 0)
  406. {
  407. var keys = KeyPropertiesCache(type);
  408. if (keys.Count() == 0)
  409. throw new DataException("查询对象中必须包含主键");
  410. sortString = keys.First().Name;
  411. }
  412. else
  413. {
  414. foreach (var item in queryModel.QuerySort)
  415. {
  416. sortString += " " + item.Field + " " + (item.IsDesc ? "DESC" : "") + ",";
  417. }
  418. sortString = sortString.TrimEnd(',');
  419. }
  420. sql = string.Format(sql, sortString, whereString, (queryModel.PageIndex - 1) * queryModel.PageSize + 1, queryModel.PageSize * queryModel.PageIndex);
  421. var grid = await unitOfWork.Connection.QueryMultipleAsync(sql, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout);
  422. #if DEBUG
  423. Trace.WriteLine(sql);
  424. #endif
  425. return new PageResult<T>()
  426. {
  427. Result = grid.Read<T>(),
  428. TotalCount = grid.Read<int>().SingleOrDefault(),
  429. PageIndex = queryModel.PageIndex,
  430. PageSize = queryModel.PageIndex
  431. };
  432. }
  433. public static async Task<IEnumerable<T>> QueryBySqlAsync<T>(this IUnitOfWork unitOfWork, string sql, int? commandTimeout = null, object param = null) where T : class
  434. {
  435. #if DEBUG
  436. Trace.WriteLine(sql);
  437. #endif
  438. return await unitOfWork.Connection.QueryAsync<T>(sql, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout, param: param);
  439. }
  440. public static async Task<T> ExecuteScalarAsync<T>(this IUnitOfWork unitOfWork, string sql, int? commandTimeout = null) where T : class
  441. {
  442. #if DEBUG
  443. Trace.WriteLine(sql);
  444. #endif
  445. return await unitOfWork.Connection.ExecuteScalarAsync<T>(sql, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout);
  446. }
  447. public static async Task ExecuteAsync(this IUnitOfWork unitOfWork, string sql)
  448. {
  449. await ExecuteAsync(unitOfWork, sql, null);
  450. }
  451. public static async Task ExecuteAsync(this IUnitOfWork unitOfWork, string sql, object obj)
  452. {
  453. await unitOfWork.Connection.ExecuteAsync(sql, obj, unitOfWork.Transaction);
  454. }
  455. public static async Task<PageResult<T>> GetPagingListAsync<T>(this IUnitOfWork unitOfWork, QueryModel queryModel, string customSql, int? commandTimeout = null) where T : class
  456. {
  457. var type = typeof(T);
  458. string sql;
  459. string tableName = GetTableName(type);
  460. sql = @"select * from ( select Row_Number()over(order by {0})rowId, * from ( " + customSql + " ) " + tableName + @" {1} )T where rowId between {2} and {3};
  461. select count(0) from ( " + customSql + " ) " + tableName + @" {1}";
  462. string whereString = " WHERE 1=1 ";
  463. string sortString = "";
  464. //Where
  465. if (queryModel.QueryParamer != null && queryModel.QueryParamer.Count > 0)
  466. {
  467. var where = TranslateWhere(queryModel.QueryParamer);
  468. if (!string.IsNullOrWhiteSpace(where))
  469. {
  470. whereString += where;
  471. }
  472. }
  473. //if (expression != null)
  474. //{
  475. // var translator = new QueryTranslator();
  476. // whereString = " where " + translator.Translate(expression);
  477. //}
  478. //Sort
  479. if (queryModel.QuerySort == null || queryModel.QuerySort.Count == 0)
  480. {
  481. var keys = KeyPropertiesCache(type);
  482. if (keys.Count() == 0)
  483. throw new DataException("查询对象中必须包含主键");
  484. sortString = keys.First().Name;
  485. }
  486. else
  487. {
  488. foreach (var item in queryModel.QuerySort)
  489. {
  490. sortString += " " + item.Field + " " + (item.IsDesc ? "DESC" : "") + ",";
  491. }
  492. sortString = sortString.TrimEnd(',');
  493. }
  494. sql = string.Format(sql, sortString, whereString, (queryModel.PageIndex - 1) * queryModel.PageSize + 1, queryModel.PageSize * queryModel.PageIndex);
  495. var grid = await unitOfWork.Connection.QueryMultipleAsync(sql, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout);
  496. #if DEBUG
  497. Trace.WriteLine(sql);
  498. #endif
  499. return new PageResult<T>()
  500. {
  501. Result = grid.Read<T>(),
  502. TotalCount = grid.Read<int>().SingleOrDefault(),
  503. PageIndex = queryModel.PageIndex,
  504. PageSize = queryModel.PageIndex
  505. };
  506. }
  507. public static async Task<bool> IsExistsAsync<T>(this IUnitOfWork unitOfWork, Expression<Func<T, bool>> expression, int? commandTimeout = null) where T : class
  508. {
  509. var type = typeof(T);
  510. string sql;
  511. //if (!GetQueries.TryGetValue(type.TypeHandle, out sql))
  512. //{
  513. //TableName
  514. string tableName = GetTableName(type);
  515. sql = @"if exists(select 1 from " + tableName + @"(nolock) {0} )
  516. select 1;
  517. select 0 ";
  518. // GetQueries[type.TypeHandle] = sql;
  519. //}
  520. string whereString = "";
  521. //Where
  522. if (expression != null)
  523. {
  524. var translator = new QueryTranslator();
  525. whereString = " where " + translator.Translate(expression);
  526. }
  527. sql = string.Format(sql, whereString);
  528. #if DEBUG
  529. Trace.WriteLine(sql);
  530. #endif
  531. var r = await unitOfWork.Connection.QueryAsync<bool>(sql, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout);
  532. return r.Single();
  533. }
  534. public static async Task<IEnumerable<T>> QueryAsync<T>(this IUnitOfWork unitOfWork, Expression<Func<T, bool>> expression, int? commandTimeout = null) where T : class
  535. {
  536. var type = typeof(T);
  537. string sql;
  538. var name = GetTableName(type);
  539. sql = "select * from " + name + "(nolock) where {0}";
  540. var translator = new QueryTranslator();
  541. string where = translator.Translate(expression);
  542. sql = string.Format(sql, where);
  543. #if DEBUG
  544. Trace.WriteLine(sql);
  545. #endif
  546. return await unitOfWork.Connection.QueryAsync<T>(sql, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout);
  547. }
  548. public static async Task<IEnumerable<T>> QueryAsync<T>(this IUnitOfWork unitOfWork, Expression<Func<T, bool>> expression, string customSql, int? commandTimeout = null) where T : class
  549. {
  550. var type = typeof(T);
  551. string sql;
  552. //if (!GetQueries.TryGetValue(type.TypeHandle, out sql))
  553. //{
  554. var name = GetTableName(type);
  555. sql = "select * from ( " + customSql + " ) " + name + " where {0}";
  556. //GetQueries[type.TypeHandle] = sql;
  557. //}
  558. var translator = new QueryTranslator();
  559. string where = translator.Translate(expression);
  560. sql = string.Format(sql, where);
  561. #if DEBUG
  562. Trace.WriteLine(sql);
  563. #endif
  564. return await unitOfWork.Connection.QueryAsync<T>(sql, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout);
  565. }
  566. public static async Task<int> CountAsync<T>(this IUnitOfWork unitOfWork, Expression<Func<T, bool>> expression, int? commandTimeout = null) where T : class
  567. {
  568. var type = typeof(T);
  569. string sql = string.Empty;
  570. //if (!GetQueries.TryGetValue(type.TypeHandle, out sql))
  571. //{
  572. var name = GetTableName(type);
  573. sql = "select count(0) from " + name + "(nolock) where {0}";
  574. var translator = new QueryTranslator();
  575. string where = translator.Translate(expression);
  576. sql = string.Format(sql, where);
  577. if (unitOfWork.DataPermission != null && unitOfWork.DataPermission.Count > 0)
  578. {//存在数据权限
  579. var allProperties = TypePropertiesCache(typeof(T));
  580. for (var i = 0; i < allProperties.Count(); i++)
  581. {
  582. var property = allProperties.ElementAt(i);
  583. var identity = property.GetCustomAttribute<DataPermissionAttribute>();
  584. if (identity == null)
  585. continue;
  586. var permission = unitOfWork.DataPermission.Find(x => x.PermissioinType == identity.PermissionType.GetValue());
  587. if (permission == null)
  588. continue;
  589. if (string.IsNullOrWhiteSpace(permission.Value))
  590. continue;
  591. sql += " AND {0} IN ({1})".Formater(property.Name, permission.Value.TrimEnd(','));
  592. }
  593. }
  594. #if DEBUG
  595. Trace.WriteLine(sql);
  596. #endif
  597. return await unitOfWork.Connection.ExecuteScalarAsync<int>(sql, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout);
  598. }
  599. /// <summary>
  600. /// 执行存储过程
  601. /// </summary>
  602. /// <param name="unitOfWork"></param>
  603. /// <param name="procName">存储过程名称</param>
  604. /// <param name="param">参数列表</param>
  605. /// <param name="commandTimeout"></param>
  606. /// <returns></returns>
  607. public static async Task<object> ExecuteStoredProcedureAsync(this IUnitOfWork unitOfWork, string procName, object param = null, int? commandTimeout = null)
  608. {
  609. return await unitOfWork.Connection.ExecuteScalarAsync(procName, param, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout, commandType: CommandType.StoredProcedure);
  610. }
  611. public static async Task<IEnumerable<T>> QueryAsync<T>(this IUnitOfWork unitOfWork, int? commandTimeout = null) where T : class
  612. {
  613. var type = typeof(T);
  614. string sql;
  615. if (!GetQueries.TryGetValue(type.TypeHandle, out sql))
  616. {
  617. var name = GetTableName(type);
  618. sql = string.Format("select * from {0}(nolock)", name);
  619. GetQueries[type.TypeHandle] = sql;
  620. }
  621. #if DEBUG
  622. Trace.WriteLine(sql);
  623. #endif
  624. return await unitOfWork.Connection.QueryAsync<T>(sql, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout);
  625. }
  626. private static string GetTableName(Type type)
  627. {
  628. string name;
  629. //if (!TypeTableName.TryGetValue(type.TypeHandle, out name))
  630. //{
  631. name = type.Name;
  632. if (type.IsInterface && name.StartsWith("I"))
  633. name = name.Substring(1);
  634. //NOTE: This as dynamic trick should be able to handle both our own Table-attribute as well as the one in EntityFramework
  635. var tableattr = type.GetCustomAttributes(false).Where(attr => attr.GetType().Name == "TableAttribute").SingleOrDefault() as
  636. dynamic;
  637. if (tableattr != null)
  638. name = tableattr.Name;
  639. // TypeTableName[type.TypeHandle] = name;
  640. //}
  641. return name;
  642. }
  643. public static long InsertNotTransfer<T>(this IUnitOfWork unitOfWork, T entityToInsert, int? commandTimeout = null) where T : class
  644. {
  645. using (SqlConnection connection = new SqlConnection(unitOfWork.ConnectionAddress))
  646. {
  647. //using (var tx = connection.BeginTransaction())
  648. //{
  649. var type = typeof(T);
  650. var name = GetTableName(type);
  651. var sb = new StringBuilder(null);
  652. sb.AppendFormat("insert into {0} (", name);
  653. var allProperties = TypePropertiesCache(type);
  654. var keyProperties = KeyPropertiesCache(type);
  655. var computedProperties = ComputedPropertiesCache(type);
  656. for (var i = 0; i < allProperties.Count(); i++)
  657. {
  658. var property = allProperties.ElementAt(i);
  659. if (keyProperties.Contains(property))
  660. {
  661. continue;
  662. }
  663. if (computedProperties.Contains(property))
  664. continue;
  665. sb.Append("[{0}]".Formater(property.Name));
  666. if (i < allProperties.Count() - 1)
  667. sb.Append(", ");
  668. }
  669. sb.Append(") values (");
  670. for (var i = 0; i < allProperties.Count(); i++)
  671. {
  672. var property = allProperties.ElementAt(i);
  673. if (keyProperties.Contains(property))
  674. {
  675. continue;
  676. }
  677. if (computedProperties.Contains(property))
  678. continue;
  679. if (property.Name.ToLower() == "createtime" || property.Name.ToLower() == "updatetime")
  680. {
  681. property.SetValue(entityToInsert, DateTime.Now);
  682. }
  683. else if (property.Name.ToLower() == "createusername" || property.Name.ToLower() == "updateusername")
  684. {
  685. if (!string.IsNullOrWhiteSpace(unitOfWork.CurrentName))
  686. {
  687. property.SetValue(entityToInsert, unitOfWork.CurrentName);
  688. }
  689. }
  690. else if (property.Name.ToLower() == "userid")
  691. {
  692. if (unitOfWork.CurrentId.HasValue)
  693. {
  694. property.SetValue(entityToInsert, unitOfWork.CurrentId.Value);
  695. }
  696. }
  697. sb.AppendFormat("@{0}", property.Name);
  698. if (i < allProperties.Count() - 1)
  699. sb.Append(", ");
  700. }
  701. sb.Append(") ");
  702. #if DEBUG
  703. Trace.WriteLine(sb.ToString());
  704. #endif
  705. connection.Execute(sb.ToString(), entityToInsert, transaction: null, commandTimeout: commandTimeout);
  706. //NOTE: would prefer to use IDENT_CURRENT('tablename') or IDENT_SCOPE but these are not available on SQLCE
  707. var r = connection.Query<int>("select isnull(@@IDENTITY,0)", transaction: null, commandTimeout: commandTimeout);
  708. // tx.Commit();
  709. return (int)r.First();
  710. }
  711. }
  712. public static async Task<bool> UpdateByConditionNoTransferAsync<T, TProperty>(this IUnitOfWork unitOfWork, Expression<Func<T, TProperty>> expression, object t) where T : class
  713. {
  714. using (SqlConnection connection = new SqlConnection(unitOfWork.ConnectionAddress))
  715. {
  716. var type = typeof(T);
  717. var psc = type.GetProperties();
  718. var ps = t.GetType().GetProperties();
  719. var set = string.Empty;
  720. var tableName = GetTableName(type);
  721. foreach (var item in ps)
  722. {
  723. if (psc.Where(x => x.Name.Equals(item.Name, StringComparison.OrdinalIgnoreCase)).Count() <= 0)
  724. throw new Exception(string.Format("表{0}中不存在字段{1}", tableName, item.Name));
  725. set += item.Name + "=@" + item.Name + ",";
  726. }
  727. var translator = new QueryTranslator();
  728. var where = translator.Translate(expression);
  729. var sql = "update {0} set {1} UpdateTime='{3}',UpdateUserName='{4}' {2}".Formater(
  730. tableName,
  731. set,
  732. string.IsNullOrEmpty(where.Trim()) ? string.Empty : " where " + where,
  733. DateTime.Now,
  734. unitOfWork.CurrentName);
  735. Trace.WriteLine(sql);
  736. var r = await connection.ExecuteAsync(sql, t, null);
  737. return r > 0;
  738. }
  739. }
  740. /// <summary>
  741. /// Inserts an entity into table "Ts" and returns identity id.
  742. /// </summary>
  743. /// <param name="connection">Open SqlConnection</param>
  744. /// <param name="entityToInsert">Entity to insert</param>
  745. /// <returns>Identity of inserted entity</returns>
  746. public static async Task<long> InsertAsync<T>(this IUnitOfWork unitOfWork, T entityToInsert, int? commandTimeout = null) where T : class
  747. {
  748. //using (var tx = connection.BeginTransaction())
  749. //{
  750. var type = typeof(T);
  751. var name = GetTableName(type);
  752. var sb = new StringBuilder(null);
  753. sb.AppendFormat("insert into {0} (", name);
  754. var allProperties = TypePropertiesCache(type);
  755. var keyProperties = KeyPropertiesCache(type);
  756. var computedProperties = ComputedPropertiesCache(type);
  757. var insertProperties = allProperties
  758. .Where(x => !keyProperties.Any(y => y == x) && !computedProperties.Any(y => y == x));
  759. for (var i = 0; i < insertProperties.Count(); i++)
  760. {
  761. var property = insertProperties.ElementAt(i);
  762. sb.Append("[{0}]".Formater(property.Name));
  763. if (i < insertProperties.Count() - 1)
  764. sb.Append(", ");
  765. }
  766. sb.Append(") values (");
  767. for (var i = 0; i < insertProperties.Count(); i++)
  768. {
  769. var property = insertProperties.ElementAt(i);
  770. if (property.Name.ToLower() == "createtime" || property.Name.ToLower() == "updatetime")
  771. {
  772. property.SetValue(entityToInsert, DateTime.Now);
  773. }
  774. else if (property.Name.ToLower() == "createusername" || property.Name.ToLower() == "updateusername")
  775. {
  776. if (!string.IsNullOrWhiteSpace(unitOfWork.CurrentName))
  777. {
  778. property.SetValue(entityToInsert, unitOfWork.CurrentName);
  779. }
  780. }
  781. else if (property.Name.ToLower() == "userid")
  782. {
  783. if (unitOfWork.CurrentId.HasValue)
  784. {
  785. property.SetValue(entityToInsert, unitOfWork.CurrentId.Value);
  786. }
  787. }
  788. sb.AppendFormat("@{0}", property.Name);
  789. if (i < insertProperties.Count() - 1)
  790. sb.Append(", ");
  791. }
  792. sb.Append(") ");
  793. Trace.WriteLine(sb.ToString());
  794. //await unitOfWork.Connection.ExecuteAsync(sb.ToString(), entityToInsert, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout);
  795. //NOTE: would prefer to use IDENT_CURRENT('tablename') or IDENT_SCOPE but these are not available on SQLCE
  796. var r = await unitOfWork.Connection.QueryAsync<int>(sb.ToString()+" select isnull(@@IDENTITY,0)",entityToInsert, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout);
  797. // tx.Commit();
  798. return (int)r.First();
  799. //}
  800. }
  801. public static void InsertBatch<T>(this IUnitOfWork unitOfWork, List<T> entityToInsert, int? commandTimeout = null) where T : class
  802. {
  803. //using (var tx = connection.BeginTransaction())
  804. //{
  805. var type = typeof(T);
  806. var name = GetTableName(type);
  807. var sb = new StringBuilder(null);
  808. sb.AppendFormat("insert into {0} (", name);
  809. var allProperties = TypePropertiesCache(type);
  810. var keyProperties = KeyPropertiesCache(type);
  811. for (var i = 0; i < allProperties.Count(); i++)
  812. {
  813. var property = allProperties.ElementAt(i);
  814. if (keyProperties.Contains(property))
  815. {
  816. continue;
  817. }
  818. sb.Append("[{0}]".Formater(property.Name));
  819. if (i < allProperties.Count() - 1)
  820. sb.Append(", ");
  821. }
  822. sb.Append(") values (");
  823. for (var i = 0; i < allProperties.Count(); i++)
  824. {
  825. var property = allProperties.ElementAt(i);
  826. if (keyProperties.Contains(property))
  827. {
  828. continue;
  829. }
  830. //if (property.Name.ToLower() == "createtime" || property.Name.ToLower() == "updatetime")
  831. //{
  832. // property.SetValue(entityToInsert, DateTime.Now);
  833. //}
  834. //else if (property.Name.ToLower() == "createusername" || property.Name.ToLower() == "updateusername")
  835. //{
  836. // if (!string.IsNullOrWhiteSpace(unitOfWork.CurrentName))
  837. // {
  838. // property.SetValue(entityToInsert, unitOfWork.CurrentName);
  839. // }
  840. //}
  841. //else if (property.Name.ToLower() == "userid")
  842. //{
  843. // if (unitOfWork.CurrentId.HasValue)
  844. // {
  845. // property.SetValue(entityToInsert, unitOfWork.CurrentId.Value);
  846. // }
  847. //}
  848. sb.AppendFormat("@{0}", property.Name);
  849. if (i < allProperties.Count() - 1)
  850. sb.Append(", ");
  851. }
  852. sb.Append(") ");
  853. unitOfWork.Connection.Execute(sb.ToString(), entityToInsert, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout);
  854. }
  855. /// <summary>
  856. /// 非自增表的插入
  857. /// </summary>
  858. /// <typeparam name="T"></typeparam>
  859. /// <param name="unitOfWork"></param>
  860. /// <param name="entityToInsert"></param>
  861. /// <param name="commandTimeout"></param>
  862. public static async Task<bool> InsertNotIdentityAsync<T>(this IUnitOfWork unitOfWork, T entityToInsert, int? commandTimeout = null) where T : class
  863. {
  864. //using (var tx = connection.BeginTransaction())
  865. //{
  866. var type = typeof(T);
  867. var name = GetTableName(type);
  868. var sb = new StringBuilder(null);
  869. sb.AppendFormat("insert into {0} (", name);
  870. var allProperties = TypePropertiesCache(type);
  871. var keyProperties = KeyPropertiesCache(type);
  872. for (var i = 0; i < allProperties.Count(); i++)
  873. {
  874. var property = allProperties.ElementAt(i);
  875. var notIdentity = property.GetCustomAttribute<NotIdentityAttribute>();
  876. if (notIdentity == null && keyProperties.Contains(property))
  877. {
  878. continue;
  879. }
  880. sb.Append("[{0}]".Formater(property.Name));
  881. if (i < allProperties.Count() - 1)
  882. sb.Append(", ");
  883. }
  884. sb.Append(") values (");
  885. for (var i = 0; i < allProperties.Count(); i++)
  886. {
  887. var property = allProperties.ElementAt(i);
  888. var Identity = property.GetCustomAttribute<NotIdentityAttribute>();
  889. //不包含自增属性并且是主键
  890. if (Identity == null && keyProperties.Contains(property))
  891. {
  892. continue;
  893. }
  894. if (property.Name.ToLower() == "createtime" || property.Name.ToLower() == "updatetime")
  895. {
  896. property.SetValue(entityToInsert, DateTime.Now);
  897. }
  898. else if (property.Name.ToLower() == "createusername" || property.Name.ToLower() == "updateusername")
  899. {
  900. if (!string.IsNullOrWhiteSpace(unitOfWork.CurrentName))
  901. {
  902. property.SetValue(entityToInsert, unitOfWork.CurrentName);
  903. }
  904. }
  905. sb.AppendFormat("@{0}", property.Name);
  906. if (i < allProperties.Count() - 1)
  907. sb.Append(", ");
  908. }
  909. sb.Append(") ");
  910. #if DEBUG
  911. Trace.WriteLine(sb.ToString());
  912. #endif
  913. await unitOfWork.Connection.ExecuteAsync(sb.ToString(), entityToInsert, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout);
  914. return true;
  915. }
  916. /// <summary>
  917. /// 向没有主键、非自增表插入数据
  918. /// </summary>
  919. /// <typeparam name="T"></typeparam>
  920. /// <param name="unitOfWork"></param>
  921. /// <param name="entityToInsert"></param>
  922. /// <param name="commandTimeout"></param>
  923. public static async Task<bool> InsertOperateLogAsync<T>(this IUnitOfWork unitOfWork, T entityToInsert, int? commandTimeout = null) where T : class
  924. {
  925. var type = typeof(T);
  926. var name = GetTableName(type);
  927. var sb = new StringBuilder(null);
  928. sb.AppendFormat("insert into {0} (", name);
  929. var allProperties = TypePropertiesCache(type);
  930. var keyProperties = KeyPropertiesCache(type);
  931. for (var i = 0; i < allProperties.Count(); i++)
  932. {
  933. var property = allProperties.ElementAt(i);
  934. var notIdentity = property.GetCustomAttribute<NotIdentityAttribute>();
  935. //if (notIdentity == null && keyProperties.Contains(property))
  936. //{
  937. // continue;
  938. //}
  939. sb.Append("[{0}]".Formater(property.Name));
  940. if (i < allProperties.Count() - 1)
  941. sb.Append(", ");
  942. }
  943. sb.Append(") values (");
  944. for (var i = 0; i < allProperties.Count(); i++)
  945. {
  946. var property = allProperties.ElementAt(i);
  947. var Identity = property.GetCustomAttribute<NotIdentityAttribute>();
  948. //不包含自增属性并且是主键
  949. //if (Identity == null && keyProperties.Contains(property))
  950. //{
  951. // continue;
  952. //}
  953. if (property.Name.ToLower() == "createtime" || property.Name.ToLower() == "updatetime")
  954. {
  955. property.SetValue(entityToInsert, DateTime.Now);
  956. }
  957. else if (property.Name.ToLower() == "createusername" || property.Name.ToLower() == "updateusername")
  958. {
  959. if (!string.IsNullOrWhiteSpace(unitOfWork.CurrentName))
  960. {
  961. property.SetValue(entityToInsert, unitOfWork.CurrentName);
  962. }
  963. }
  964. sb.AppendFormat("@{0}", property.Name);
  965. if (i < allProperties.Count() - 1)
  966. sb.Append(", ");
  967. }
  968. sb.Append(") ");
  969. #if DEBUG
  970. Trace.WriteLine(sb.ToString());
  971. #endif
  972. await unitOfWork.Connection.ExecuteAsync(sb.ToString(), entityToInsert, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout);
  973. return true;
  974. }
  975. /// <summary>
  976. /// 根据某个字段修改表数据
  977. /// </summary>
  978. /// <typeparam name="T"></typeparam>
  979. /// <param name="unitOfWork"></param>
  980. /// <param name="field"></param>
  981. /// <param name="value"></param>
  982. /// <param name="pk"></param>
  983. /// <returns></returns>
  984. public static async Task<bool> UpdateByPrimaryKeyAsync<T>(this IUnitOfWork unitOfWork, string field, object value, int pk) where T : class
  985. {
  986. var type = typeof(T);
  987. await OperateLog<T>(unitOfWork, field, value, pk, type);
  988. var tableName = GetTableName(type);
  989. string where = @" where id=@id";
  990. string sql = "update {0} set {1} = @value,UpdateTime=@updateTime,UpdateUserName=@updateUserName".Formater(tableName, field);
  991. if (pk != 0)
  992. {
  993. sql += where;
  994. }
  995. else
  996. {
  997. throw new Exception("未传入正确的主键");
  998. }
  999. #if DEBUG
  1000. Trace.WriteLine(sql);
  1001. #endif
  1002. var r = await unitOfWork.Connection.ExecuteAsync(sql, new { value = value, id = pk, updateTime = DateTime.Now, updateUserName = unitOfWork.CurrentName }, transaction: unitOfWork.Transaction, commandType: null);
  1003. return r > 0 ? true : false;
  1004. }
  1005. private static async Task<bool> OperateLog<T>(IUnitOfWork unitOfWork, string field, object value, int pk, Type type, DateTime? createTime = null) where T : class
  1006. {
  1007. if (createTime == null)
  1008. createTime = DateTime.Now;
  1009. var allProperties = TypePropertiesCache(type);
  1010. string logTableName = string.Empty;
  1011. string description = string.Empty;
  1012. bool isTrack = false;
  1013. var newValue = value;
  1014. var propertyValue = value;
  1015. foreach (var item in allProperties)
  1016. {
  1017. if (!item.Name.Equals(field, StringComparison.OrdinalIgnoreCase))
  1018. continue;
  1019. var track = item.GetCustomAttribute<TrackAttribute>();
  1020. if (track == null)
  1021. continue;
  1022. isTrack = true;
  1023. description = track.Description;
  1024. if (item.PropertyType.IsEnum && value.GetType().Equals(typeof(int)))
  1025. {
  1026. newValue = item.PropertyType.GetEnumName(value.ToString().TryConvertInt32());
  1027. propertyValue = item.PropertyType.GetField(newValue.ToString()).GetValue(null);
  1028. }
  1029. else if (item.PropertyType.IsEnum)
  1030. {
  1031. newValue = value.ToString();
  1032. propertyValue = item.PropertyType.GetField(value.ToString()).GetValue(null);
  1033. }
  1034. break;
  1035. }
  1036. if (isTrack)
  1037. {
  1038. var trackTable = type.GetCustomAttribute<TrackTableAttribute>();
  1039. var orign = await unitOfWork.GetAsync<T>(pk);
  1040. var orignType = orign.GetType();
  1041. if (
  1042. orignType.GetProperty(field) != null && (
  1043. (orignType.GetProperty(field).GetValue(orign) != null && orignType.GetProperty(field).GetValue(orign).Equals(propertyValue))
  1044. ||
  1045. (orignType.GetProperty(field).GetValue(orign) == null && propertyValue == null))
  1046. )
  1047. {
  1048. return false;
  1049. }
  1050. if (trackTable == null)
  1051. throw new Exception("TrackTable未设定,请检查实体类");
  1052. logTableName = GetTableName(trackTable.Table);
  1053. var allLogProperties = TypePropertiesCache(trackTable.Table);
  1054. StringBuilder sb = new StringBuilder();
  1055. sb.AppendFormat("insert into {0}", logTableName);
  1056. sb.Append("(");
  1057. for (var i = 0; i < allLogProperties.Count(); i++)
  1058. {
  1059. var property = allLogProperties.ElementAt(i);
  1060. sb.Append(property.Name);
  1061. if (i < allLogProperties.Count() - 1)
  1062. sb.Append(", ");
  1063. }
  1064. sb.Append(")");
  1065. sb.Append("values");
  1066. sb.Append("(");
  1067. for (var i = 0; i < allLogProperties.Count(); i++)
  1068. {
  1069. var property = allLogProperties.ElementAt(i);
  1070. sb.AppendFormat("@{0}", property.Name);
  1071. if (i < allLogProperties.Count() - 1)
  1072. sb.Append(", ");
  1073. }
  1074. sb.Append(")");
  1075. var instance = Activator.CreateInstance(trackTable.Table);
  1076. var properties = instance.GetType().GetProperties().Where(p => p.PropertyType.IsPublic && p.CanWrite).ToList();
  1077. foreach (var item in properties)
  1078. {
  1079. switch (item.Name.ToLower())
  1080. {
  1081. case "id":
  1082. item.SetValue(instance, pk);
  1083. break;
  1084. case "field":
  1085. item.SetValue(instance, field);
  1086. break;
  1087. case "fielddesc":
  1088. item.SetValue(instance, description);
  1089. break;
  1090. case "oldvalue":
  1091. var result = orignType.GetProperty(field).GetValue(orign) ?? orignType.GetProperty(field);
  1092. item.SetValue(instance, result == null ? "" : result.ToString());
  1093. break;
  1094. case "newvalue":
  1095. item.SetValue(instance, newValue == null ? "" : newValue.ToString());
  1096. break;
  1097. case "createtime":
  1098. item.SetValue(instance, createTime.Value);
  1099. break;
  1100. case "createusername":
  1101. item.SetValue(instance, string.IsNullOrWhiteSpace(unitOfWork.CurrentName) ? "System" : unitOfWork.CurrentName);
  1102. break;
  1103. case "updatetime":
  1104. item.SetValue(instance, DateTime.Now);
  1105. break;
  1106. case "updateusername":
  1107. item.SetValue(instance, string.IsNullOrWhiteSpace(unitOfWork.CurrentName) ? "System" : unitOfWork.CurrentName);
  1108. break;
  1109. }
  1110. }
  1111. #if DEBUG
  1112. Trace.WriteLine(sb.ToString());
  1113. #endif
  1114. await unitOfWork.Connection.ExecuteAsync(sb.ToString(), instance, transaction: unitOfWork.Transaction, commandType: null);
  1115. }
  1116. return true;
  1117. }
  1118. public static async Task<bool> UpdateByPrimaryKeyAsync<T, TProperty>(this IUnitOfWork unitOfWork, Expression<Func<T, TProperty>> expression, int id, object value) where T : class
  1119. {
  1120. var type = typeof(T);
  1121. string field = (expression.Body as System.Linq.Expressions.MemberExpression).Member.Name;
  1122. await OperateLog<T>(unitOfWork, field, value, id, type);
  1123. var tableName = GetTableName(type);
  1124. string sql = "update {0} set {1} = @value,UpdateTime=@updateTime,UpdateUserName=@updateUserName where id=@id".Formater(tableName, field);
  1125. #if DEBUG
  1126. Trace.WriteLine(sql);
  1127. #endif
  1128. var o = await unitOfWork.Connection.ExecuteAsync(sql, new { value = value, id = id, updateTime = DateTime.Now, updateUserName = unitOfWork.CurrentName }, transaction: unitOfWork.Transaction, commandType: null);
  1129. return o > 0 ? true : false;
  1130. }
  1131. public static async Task<bool> UpdateByConditionAsync<T, TProperty>(this IUnitOfWork unitOfWork, Expression<Func<T, TProperty>> expression, string[] propertys, object[] values) where T : class
  1132. {
  1133. var type = typeof(T);
  1134. var set = string.Empty;
  1135. var dic = new Dictionary<string, object>();
  1136. for (int i = 0; i < propertys.Length; i++)
  1137. {
  1138. set += propertys[i] + "=@" + propertys[i] + ",";
  1139. dic.Add("@" + propertys[i], values[i]);
  1140. }
  1141. dic.Add("@updateTime", DateTime.Now);
  1142. dic.Add("@updateUserName", unitOfWork.CurrentName);
  1143. var tableName = GetTableName(type);
  1144. var translator = new QueryTranslator();
  1145. var where = translator.Translate(expression);
  1146. var sql = "update {0} set {1} UpdateTime=@updateTime,UpdateUserName=@updateUserName {2}".Formater(tableName, set, string.IsNullOrEmpty(where.Trim()) ? string.Empty : " where " + where);
  1147. #if DEBUG
  1148. Trace.WriteLine(sql);
  1149. #endif
  1150. var r = await unitOfWork.Connection.ExecuteAsync(sql, dic, transaction: unitOfWork.Transaction, commandType: null);
  1151. return r > 0 ? true : false;
  1152. }
  1153. public static async Task<bool> UpdateByConditionAsync<T, TProperty>(this IUnitOfWork unitOfWork, Expression<Func<T, TProperty>> expression, object t) where T : class
  1154. {
  1155. var type = typeof(T);
  1156. var psc = type.GetProperties();
  1157. var ps = t.GetType().GetProperties();
  1158. var set = string.Empty;
  1159. var tableName = GetTableName(type);
  1160. foreach (var item in ps)
  1161. {
  1162. if (psc.Where(x => x.Name.Equals(item.Name, StringComparison.OrdinalIgnoreCase)).Count() <= 0)
  1163. throw new Exception(string.Format("表{0}中不存在字段{1}", tableName, item.Name));
  1164. set += item.Name + "=@" + item.Name + ",";
  1165. }
  1166. var translator = new QueryTranslator();
  1167. var where = translator.Translate(expression);
  1168. var sql = "update {0} set {1} UpdateTime='{3}',UpdateUserName='{4}' {2}".Formater(
  1169. tableName,
  1170. set,
  1171. string.IsNullOrEmpty(where.Trim()) ? string.Empty : " where " + where,
  1172. DateTime.Now,
  1173. unitOfWork.CurrentName);
  1174. #if DEBUG
  1175. Trace.WriteLine(sql);
  1176. #endif
  1177. var r = await unitOfWork.Connection.ExecuteAsync(sql, t, transaction: unitOfWork.Transaction, commandType: null);
  1178. return r > 0 ? true : false;
  1179. }
  1180. public static async Task<bool> UpdateByConditionAsync<T, TProperty>(this IUnitOfWork unitOfWork, Expression<Func<T, TProperty>> expression, string sql) where T : class
  1181. {
  1182. var type = typeof(T);
  1183. var psc = type.GetProperties();
  1184. var tableName = GetTableName(type);
  1185. var where = string.Empty;
  1186. if (expression != null)
  1187. {
  1188. var translator = new QueryTranslator();
  1189. where = translator.Translate(expression);
  1190. }
  1191. if (!string.IsNullOrEmpty(where.Trim()))
  1192. {
  1193. if (sql.ToLower().Contains("where"))
  1194. {
  1195. sql += where;
  1196. }
  1197. else
  1198. {
  1199. sql += " where " + where;
  1200. }
  1201. }
  1202. #if DEBUG
  1203. Trace.WriteLine(sql);
  1204. #endif
  1205. var obj = await unitOfWork.Connection.ExecuteAsync(sql, new { }, transaction: unitOfWork.Transaction, commandType: null);
  1206. return obj > 0 ? true : false;
  1207. }
  1208. public static async Task<int> CountAsync<T>(this IUnitOfWork unitOfWork, Expression<Func<T, bool>> expression, QueryModel model, int? commandTimeout = null) where T : class
  1209. {
  1210. var type = typeof(T);
  1211. string sql;
  1212. var name = GetTableName(type);
  1213. sql = "select count(0) from " + name + " (NOLOCK) where 1=1 {0}";
  1214. var translator = new QueryTranslator();
  1215. string where = translator.Translate(expression);
  1216. sql = string.Format(sql, string.IsNullOrEmpty(where) ? "" : (" and " + where));
  1217. if (model != null && model.DataPermission != null && model.DataPermission.Count > 0)
  1218. {
  1219. //存在数据权限
  1220. var allProperties = TypePropertiesCache(typeof(T));
  1221. for (var i = 0; i < allProperties.Count(); i++)
  1222. {
  1223. var property = allProperties.ElementAt(i);
  1224. var identity = property.GetCustomAttribute<DataPermissionAttribute>();
  1225. if (identity == null)
  1226. continue;
  1227. var permission = model.DataPermission.Find(x => x.PermissioinType == identity.PermissionType.GetValue());
  1228. if (permission == null)
  1229. continue;
  1230. if (string.IsNullOrWhiteSpace(permission.Value))
  1231. continue;
  1232. sql += " AND {0} IN ({1})".Formater(property.Name, permission.Value.TrimEnd(','));
  1233. }
  1234. }
  1235. #if DEBUG
  1236. Trace.WriteLine(sql);
  1237. #endif
  1238. return await unitOfWork.Connection.ExecuteScalarAsync<int>(sql, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout);
  1239. }
  1240. public static async Task<IDictionary<int, int>> GroupCountAsync<T, TProperty>(this IUnitOfWork unitOfWork, Expression<Func<T, TProperty>> propName, Expression<Func<T, bool>> expression = null, QueryModel queryModel = null, int? commandTimeout = null) where T : class
  1241. {
  1242. string field = (propName.Body as System.Linq.Expressions.MemberExpression).Member.Name;
  1243. var name = GetTableName(typeof(T));
  1244. string sql = string.Format(" SELECT {1} AS [Status] , COUNT(0) AS [Count] FROM {0} (NOLOCK) ", name, field);
  1245. sql += " where 1=1 ";
  1246. if (expression != null)
  1247. {
  1248. var translator = new QueryTranslator();
  1249. var where = translator.Translate(expression);
  1250. sql += string.IsNullOrEmpty(where.Trim()) ? string.Empty : " and " + where;
  1251. }
  1252. if (unitOfWork.DataPermission != null && unitOfWork.DataPermission.Count > 0)
  1253. {//存在数据权限
  1254. var allProperties = TypePropertiesCache(typeof(T));
  1255. for (var i = 0; i < allProperties.Count(); i++)
  1256. {
  1257. var property = allProperties.ElementAt(i);
  1258. var identity = property.GetCustomAttribute<DataPermissionAttribute>();
  1259. if (identity == null)
  1260. continue;
  1261. var permission = unitOfWork.DataPermission.Find(x => x.PermissioinType == identity.PermissionType.GetValue());
  1262. if (permission == null)
  1263. continue;
  1264. if (string.IsNullOrWhiteSpace(permission.Value))
  1265. continue;
  1266. sql += " AND {0} IN ({1})".Formater(property.Name, permission.Value.TrimEnd(','));
  1267. }
  1268. }
  1269. sql += string.Format(" GROUP BY {0} ", field);
  1270. #if DEBUG
  1271. Trace.WriteLine(sql);
  1272. #endif
  1273. var result = await unitOfWork.Connection.QueryAsync<dynamic>(sql, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout);
  1274. IDictionary<int, int> dic = new Dictionary<int, int>();
  1275. foreach (var item in result)
  1276. {
  1277. dic.Add(item.Status, item.Count);
  1278. }
  1279. return dic;
  1280. }
  1281. public static async Task<bool> UpdateListAsync<T>(this IUnitOfWork unitOfWork, IList<T> list, int? commandTimeout = null) where T : class
  1282. {
  1283. if (list.Count == 0)
  1284. return false;
  1285. var proxy = list.First() as IProxy;
  1286. if (proxy != null)
  1287. {
  1288. if (!proxy.IsDirty) return false;
  1289. }
  1290. var type = typeof(T);
  1291. var keyProperties = KeyPropertiesCache(type);
  1292. if (keyProperties.Count() == 0)
  1293. throw new ArgumentException("实体必须包含一个主键 [Key] 属性");
  1294. var key = keyProperties.FirstOrDefault();
  1295. var name = GetTableName(type);
  1296. var allProperties = TypePropertiesCache(type);
  1297. var nonIdProps = allProperties.Where(a => !keyProperties.Contains(a));
  1298. var sb = new StringBuilder();
  1299. foreach (var entityToUpdate in list)
  1300. {
  1301. sb.Append("update {0} set ".Formater(name));
  1302. for (var i = 0; i < nonIdProps.Count(); i++)
  1303. {
  1304. var property = nonIdProps.ElementAt(i);
  1305. var value = property.GetValue(entityToUpdate);
  1306. if (property.Name.ToLower() == "createtime" || property.Name.ToLower() == "createusername")
  1307. continue;
  1308. if (property.Name.ToLower() == "updatetime")
  1309. {
  1310. property.SetValue(entityToUpdate, DateTime.Now);
  1311. }
  1312. else if (property.Name.ToLower() == "updateusername" || property.Name.ToLower() == "shelvesusername")// || property.Name.ToLower() == "allottedusername")
  1313. {
  1314. if (!string.IsNullOrWhiteSpace(unitOfWork.CurrentName))
  1315. {
  1316. property.SetValue(entityToUpdate, unitOfWork.CurrentName);
  1317. }
  1318. }
  1319. //add gyp 20160608 非ERP操作的(例:PDA)动态设置值
  1320. else if (property.Name.ToLower() == "userid" || property.Name.ToLower() == "shelvesuserid")// || property.Name.ToLower() == "allotteduserid")
  1321. {
  1322. if (unitOfWork.CurrentId.HasValue)
  1323. {
  1324. property.SetValue(entityToUpdate, unitOfWork.CurrentId.Value);
  1325. }
  1326. }
  1327. if (property.GetValue(entityToUpdate) == null)
  1328. {
  1329. sb.AppendFormat("[{0}] = null", property.Name, property.GetValue(entityToUpdate));
  1330. }
  1331. else if (property.PropertyType == typeof(string) || property.PropertyType == typeof(DateTime) || property.PropertyType == typeof(DateTime?))
  1332. {
  1333. sb.AppendFormat("[{0}] = '{1}'", property.Name, property.GetValue(entityToUpdate).ToString().Replace("'", "''"));
  1334. }
  1335. else
  1336. {
  1337. sb.AppendFormat("[{0}] = {1}", property.Name, property.GetValue(entityToUpdate));
  1338. }
  1339. if (i < nonIdProps.Count() - 1)
  1340. sb.AppendFormat(", ");
  1341. }
  1342. sb.Append(" where ");
  1343. for (var i = 0; i < keyProperties.Count(); i++)
  1344. {
  1345. var property = keyProperties.ElementAt(i);
  1346. sb.AppendFormat("[{0}] = {1}", property.Name, property.GetValue(entityToUpdate));
  1347. if (i < keyProperties.Count() - 1)
  1348. sb.AppendFormat(" and ");
  1349. }
  1350. sb.AppendLine();
  1351. }
  1352. var updated = await unitOfWork.Connection.ExecuteAsync(sb.ToString(), null, commandTimeout: commandTimeout, transaction: unitOfWork.Transaction);
  1353. return updated > 0;
  1354. }
  1355. /// <summary>
  1356. /// Updates entity in table "Ts", checks if the entity is modified if the entity is tracked by the Get() extension.
  1357. /// </summary>
  1358. /// <typeparam name="T">Type to be updated</typeparam>
  1359. /// <param name="connection">Open SqlConnection</param>
  1360. /// <param name="entityToUpdate">Entity to be updated</param>
  1361. /// <returns>true if updated, false if not found or not modified (tracked entities)</returns>
  1362. public static async Task<bool> UpdateAsync<T>(this IUnitOfWork unitOfWork, T entityToUpdate, int? commandTimeout = null) where T : class
  1363. {
  1364. var proxy = entityToUpdate as IProxy;
  1365. if (proxy != null)
  1366. {
  1367. if (!proxy.IsDirty) return false;
  1368. }
  1369. var type = typeof(T);
  1370. var keyProperties = KeyPropertiesCache(type);
  1371. if (keyProperties.Count() == 0)
  1372. throw new ArgumentException("实体必须包含一个主键 [Key] 属性");
  1373. var key = keyProperties.FirstOrDefault();
  1374. var name = GetTableName(type);
  1375. var sb = new StringBuilder();
  1376. sb.AppendFormat("update {0} set ", name);
  1377. var allProperties = TypePropertiesCache(type);
  1378. var computedProperties = ComputedPropertiesCache(type);
  1379. var nonIdProps = allProperties.Where(a => !keyProperties.Contains(a) && !computedProperties.Contains(a));
  1380. DateTime operTime = DateTime.Now;
  1381. for (var i = 0; i < nonIdProps.Count(); i++)
  1382. {
  1383. var property = nonIdProps.ElementAt(i);
  1384. var value = property.GetValue(entityToUpdate);
  1385. if (property.Name.ToLower() == "createtime" || property.Name.ToLower() == "createusername")
  1386. continue;
  1387. if (property.Name.ToLower() == "updatetime")
  1388. {
  1389. property.SetValue(entityToUpdate, DateTime.Now);
  1390. }
  1391. else if (property.Name.ToLower() == "updateusername" || property.Name.ToLower() == "shelvesusername")// || property.Name.ToLower() == "allottedusername")
  1392. {
  1393. if (!string.IsNullOrWhiteSpace(unitOfWork.CurrentName))
  1394. {
  1395. property.SetValue(entityToUpdate, unitOfWork.CurrentName);
  1396. }
  1397. }
  1398. //add gyp 20160608 非ERP操作的(例:PDA)动态设置值
  1399. else if (property.Name.ToLower() == "userid" || property.Name.ToLower() == "shelvesuserid")// || property.Name.ToLower() == "allotteduserid")
  1400. {
  1401. if (unitOfWork.CurrentId.HasValue)
  1402. {
  1403. property.SetValue(entityToUpdate, unitOfWork.CurrentId.Value);
  1404. }
  1405. }
  1406. sb.AppendFormat("[{0}] = @{1}", property.Name, property.Name);
  1407. if (i < nonIdProps.Count() - 1)
  1408. sb.AppendFormat(", ");
  1409. await OperateLog<T>(unitOfWork, property.Name, value, key.GetValue(entityToUpdate).ToString().TryConvertInt32(), type, operTime);
  1410. }
  1411. sb.Append(" where ");
  1412. for (var i = 0; i < keyProperties.Count(); i++)
  1413. {
  1414. var property = keyProperties.ElementAt(i);
  1415. sb.AppendFormat("[{0}] = @{1}", property.Name, property.Name);
  1416. if (i < keyProperties.Count() - 1)
  1417. sb.AppendFormat(" and ");
  1418. }
  1419. #if DEBUG
  1420. Trace.WriteLine(sb.ToString());
  1421. #endif
  1422. var updated = await unitOfWork.Connection.ExecuteAsync(sb.ToString(), entityToUpdate, commandTimeout: commandTimeout, transaction: unitOfWork.Transaction);
  1423. return updated > 0;
  1424. }
  1425. /// <summary>
  1426. /// Delete entity in table "Ts".
  1427. /// </summary>
  1428. /// <typeparam name="T">Type of entity</typeparam>
  1429. /// <param name="connection">Open SqlConnection</param>
  1430. /// <param name="entityToDelete">Entity to delete</param>
  1431. /// <returns>true if deleted, false if not found</returns>
  1432. public static async Task<bool> DeleteAsync<T>(this IUnitOfWork unitOfWork, T entityToDelete, int? commandTimeout = null) where T : class
  1433. {
  1434. var type = typeof(T);
  1435. var keyProperties = KeyPropertiesCache(type);
  1436. if (keyProperties.Count() == 0)
  1437. throw new ArgumentException("实体必须包含一个主键 [Key] 属性");
  1438. var name = GetTableName(type);
  1439. var sb = new StringBuilder();
  1440. sb.AppendFormat("delete from {0} where ", name);
  1441. for (var i = 0; i < keyProperties.Count(); i++)
  1442. {
  1443. var property = keyProperties.ElementAt(i);
  1444. sb.AppendFormat("[{0}] = @{1}", property.Name, property.Name);
  1445. if (i < keyProperties.Count() - 1)
  1446. sb.AppendFormat(" and ");
  1447. }
  1448. #if DEBUG
  1449. Trace.WriteLine(sb.ToString());
  1450. #endif
  1451. var deleted = await unitOfWork.Connection.ExecuteAsync(sb.ToString(), entityToDelete, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout);
  1452. return deleted > 0;
  1453. }
  1454. public static async Task<bool> DeleteAsync<T>(this IUnitOfWork unitOfWork, List<T> list, int? commandTimeout = null) where T : class
  1455. {
  1456. var type = typeof(T);
  1457. var keyProperties = KeyPropertiesCache(type);
  1458. if (keyProperties.Count() == 0)
  1459. throw new ArgumentException("实体必须包含一个主键 [Key] 属性");
  1460. var name = GetTableName(type);
  1461. var sb = new StringBuilder();
  1462. sb.AppendFormat("delete from {0} where ", name);
  1463. for (var i = 0; i < keyProperties.Count(); i++)
  1464. {
  1465. var property = keyProperties.ElementAt(i);
  1466. sb.AppendFormat("[{0}] = @{1}", property.Name, property.Name);
  1467. if (i < keyProperties.Count() - 1)
  1468. sb.AppendFormat(" and ");
  1469. }
  1470. var deleted = 0;
  1471. foreach (var item in list)
  1472. {
  1473. #if DEBUG
  1474. Trace.WriteLine(sb.ToString());
  1475. #endif
  1476. deleted += await unitOfWork.Connection.ExecuteAsync(sb.ToString(), item, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout);
  1477. }
  1478. return deleted > 0;
  1479. }
  1480. public static async Task<bool> DeleteByIdAsync<T>(this IUnitOfWork unitOfWork, int id) where T : class
  1481. {
  1482. var type = typeof(T);
  1483. var tableName = GetTableName(type);
  1484. string sql = "delete from {0} where id=@id".Formater(tableName);
  1485. #if DEBUG
  1486. Trace.WriteLine(sql);
  1487. #endif
  1488. var qty = await unitOfWork.Connection.ExecuteAsync(sql, new { id = id, updateTime = DateTime.Now, updateUserName = unitOfWork.CurrentName }, transaction: unitOfWork.Transaction, commandType: null);
  1489. return qty > 0 ? true : false;
  1490. }
  1491. public static void BulkToDB<T>(this SqlConnection conn, List<T> t, SqlTransaction tran)
  1492. {
  1493. var type = typeof(T);
  1494. var name = GetTableName(type);
  1495. var allProperties = TypePropertiesCache(type);
  1496. DataTable dt = new DataTable();
  1497. for (int i = 0; i < allProperties.Count(); i++)
  1498. {
  1499. var property = allProperties.ElementAt(i);
  1500. dt.Columns.Add(property.Name);
  1501. }
  1502. foreach (var item in t)
  1503. {
  1504. var itemType = item.GetType();
  1505. var properties = TypePropertiesCache(itemType);
  1506. DataRow dr = dt.NewRow();
  1507. for (int i = 0; i < properties.Count(); i++)
  1508. {
  1509. var property = properties.ElementAt(i);
  1510. if (property.Name.Equals("id", StringComparison.OrdinalIgnoreCase))
  1511. continue;
  1512. if (property.PropertyType.IsEnum)
  1513. {
  1514. //alter zkp 20160524
  1515. dr[property.Name] = Convert.ToInt32(property.GetValue(item));
  1516. }
  1517. else
  1518. {
  1519. dr[property.Name] = property.GetValue(item);
  1520. }
  1521. }
  1522. dt.Rows.Add(dr);
  1523. }
  1524. using (SqlBulkCopy bulkCopy = new SqlBulkCopy(conn, SqlBulkCopyOptions.Default, tran))
  1525. {
  1526. bulkCopy.DestinationTableName = name;
  1527. for (int i = 0; i < allProperties.Count(); i++)
  1528. {
  1529. var property = allProperties.ElementAt(i);
  1530. if (property.Name.Equals("id", StringComparison.OrdinalIgnoreCase))
  1531. continue;
  1532. bulkCopy.ColumnMappings.Add(property.Name, property.Name);
  1533. }
  1534. bulkCopy.BatchSize = t.Count;
  1535. bulkCopy.WriteToServer(dt);
  1536. }
  1537. }
  1538. public static void BulkToDB<T>(this SqlConnection conn, List<T> t)
  1539. {
  1540. var type = typeof(T);
  1541. var name = GetTableName(type);
  1542. var allProperties = TypePropertiesCache(type);
  1543. DataTable dt = new DataTable();
  1544. for (int i = 0; i < allProperties.Count(); i++)
  1545. {
  1546. var property = allProperties.ElementAt(i);
  1547. dt.Columns.Add(property.Name);
  1548. }
  1549. foreach (var item in t)
  1550. {
  1551. var itemType = item.GetType();
  1552. var properties = TypePropertiesCache(itemType);
  1553. DataRow dr = dt.NewRow();
  1554. for (int i = 0; i < properties.Count(); i++)
  1555. {
  1556. var property = properties.ElementAt(i);
  1557. if (property.Name.Equals("id", StringComparison.OrdinalIgnoreCase))
  1558. continue;
  1559. if (property.PropertyType.IsEnum)
  1560. {
  1561. //alter zkp 20160524
  1562. dr[property.Name] = Convert.ToInt32(property.GetValue(item));
  1563. }
  1564. else
  1565. {
  1566. dr[property.Name] = property.GetValue(item);
  1567. }
  1568. }
  1569. dt.Rows.Add(dr);
  1570. }
  1571. using (SqlBulkCopy bulkCopy = new SqlBulkCopy(conn, SqlBulkCopyOptions.Default, null))
  1572. {
  1573. bulkCopy.DestinationTableName = name;
  1574. for (int i = 0; i < allProperties.Count(); i++)
  1575. {
  1576. var property = allProperties.ElementAt(i);
  1577. if (property.Name.Equals("id", StringComparison.OrdinalIgnoreCase))
  1578. continue;
  1579. bulkCopy.ColumnMappings.Add(property.Name, property.Name);
  1580. }
  1581. bulkCopy.BatchSize = t.Count;
  1582. bulkCopy.WriteToServer(dt);
  1583. }
  1584. }
  1585. public static async Task<bool> BulkToDBAsync<T>(this IUnitOfWork unitOfWork, List<T> t)
  1586. {
  1587. var type = typeof(T);
  1588. var name = GetTableName(type);
  1589. var allProperties = TypePropertiesCache(type);
  1590. allProperties = allProperties.Where(p => !p.GetCustomAttributes(true).Any(a => a is NoDbAttribute)).ToList();
  1591. DataTable dt = new DataTable();
  1592. for (int i = 0; i < allProperties.Count(); i++)
  1593. {
  1594. var property = allProperties.ElementAt(i);
  1595. dt.Columns.Add(property.Name);
  1596. }
  1597. foreach (var item in t)
  1598. {
  1599. var itemType = item.GetType();
  1600. var properties = TypePropertiesCache(itemType);
  1601. properties = properties.Where(p => !p.GetCustomAttributes(true).Any(a => a is NoDbAttribute)).ToList();
  1602. DataRow dr = dt.NewRow();
  1603. for (int i = 0; i < properties.Count(); i++)
  1604. {
  1605. var property = properties.ElementAt(i);
  1606. if (property.Name.Equals("id", StringComparison.OrdinalIgnoreCase))
  1607. continue;
  1608. if (property.PropertyType.IsEnum)
  1609. {
  1610. //alter zkp 20160524
  1611. dr[property.Name] = Convert.ToInt32(property.GetValue(item));
  1612. }
  1613. else
  1614. {
  1615. dr[property.Name] = property.GetValue(item);
  1616. }
  1617. }
  1618. dt.Rows.Add(dr);
  1619. }
  1620. var connection = unitOfWork.Connection;
  1621. using (SqlBulkCopy bulkCopy = new SqlBulkCopy((SqlConnection)unitOfWork.Connection, SqlBulkCopyOptions.Default, (SqlTransaction)unitOfWork.Transaction))
  1622. {
  1623. if (connection.State == ConnectionState.Closed)
  1624. connection.Open();
  1625. bulkCopy.DestinationTableName = name;
  1626. for (int i = 0; i < allProperties.Count(); i++)
  1627. {
  1628. var property = allProperties.ElementAt(i);
  1629. if (property.Name.Equals("id", StringComparison.OrdinalIgnoreCase))
  1630. continue;
  1631. bulkCopy.ColumnMappings.Add(property.Name, property.Name);
  1632. }
  1633. bulkCopy.BatchSize = t.Count;
  1634. bulkCopy.BulkCopyTimeout = 120;
  1635. await bulkCopy.WriteToServerAsync(dt);
  1636. //unitOfWork.Connection.Close();
  1637. }
  1638. return true;
  1639. }
  1640. class ProxyGenerator
  1641. {
  1642. private static readonly Dictionary<Type, object> TypeCache = new Dictionary<Type, object>();
  1643. private static AssemblyBuilder GetAsmBuilder(string name)
  1644. {
  1645. var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName { Name = name },
  1646. AssemblyBuilderAccess.Run); //NOTE: to save, use RunAndSave
  1647. return assemblyBuilder;
  1648. }
  1649. public static T GetClassProxy<T>()
  1650. {
  1651. // A class proxy could be implemented if all properties are virtual
  1652. // otherwise there is a pretty dangerous case where internal actions will not update dirty tracking
  1653. throw new NotImplementedException();
  1654. }
  1655. public static T GetInterfaceProxy<T>()
  1656. {
  1657. Type typeOfT = typeof(T);
  1658. if (TypeCache.ContainsKey(typeOfT))
  1659. {
  1660. return (T)TypeCache[typeOfT];
  1661. }
  1662. var assemblyBuilder = GetAsmBuilder(typeOfT.Name);
  1663. var moduleBuilder = assemblyBuilder.DefineDynamicModule("SqlMapperExtensions." + typeOfT.Name); //NOTE: to save, add "asdasd.dll" parameter
  1664. var interfaceType = typeof(SqlMapperExtensions.IProxy);
  1665. var typeBuilder = moduleBuilder.DefineType(typeOfT.Name + "_" + Guid.NewGuid(),
  1666. TypeAttributes.Public | TypeAttributes.Class);
  1667. typeBuilder.AddInterfaceImplementation(typeOfT);
  1668. typeBuilder.AddInterfaceImplementation(interfaceType);
  1669. //create our _isDirty field, which implements IProxy
  1670. var setIsDirtyMethod = CreateIsDirtyProperty(typeBuilder);
  1671. // Generate a field for each property, which implements the T
  1672. foreach (var property in typeof(T).GetProperties())
  1673. {
  1674. var isId = property.GetCustomAttributes(true).Any(a => a is KeyAttribute);
  1675. CreateProperty<T>(typeBuilder, property.Name, property.PropertyType, setIsDirtyMethod, isId);
  1676. }
  1677. var generatedType = typeBuilder.CreateTypeInfo().AsType();
  1678. //assemblyBuilder.Save(name + ".dll"); //NOTE: to save, uncomment
  1679. var generatedObject = Activator.CreateInstance(generatedType);
  1680. TypeCache.Add(typeOfT, generatedObject);
  1681. return (T)generatedObject;
  1682. }
  1683. private static MethodInfo CreateIsDirtyProperty(TypeBuilder typeBuilder)
  1684. {
  1685. var propType = typeof(bool);
  1686. var field = typeBuilder.DefineField("_" + "IsDirty", propType, FieldAttributes.Private);
  1687. var property = typeBuilder.DefineProperty("IsDirty",
  1688. System.Reflection.PropertyAttributes.None,
  1689. propType,
  1690. new Type[] { propType });
  1691. const MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.NewSlot | MethodAttributes.SpecialName |
  1692. MethodAttributes.Final | MethodAttributes.Virtual | MethodAttributes.HideBySig;
  1693. // Define the "get" and "set" accessor methods
  1694. var currGetPropMthdBldr = typeBuilder.DefineMethod("get_" + "IsDirty",
  1695. getSetAttr,
  1696. propType,
  1697. Type.EmptyTypes);
  1698. var currGetIL = currGetPropMthdBldr.GetILGenerator();
  1699. currGetIL.Emit(OpCodes.Ldarg_0);
  1700. currGetIL.Emit(OpCodes.Ldfld, field);
  1701. currGetIL.Emit(OpCodes.Ret);
  1702. var currSetPropMthdBldr = typeBuilder.DefineMethod("set_" + "IsDirty",
  1703. getSetAttr,
  1704. null,
  1705. new Type[] { propType });
  1706. var currSetIL = currSetPropMthdBldr.GetILGenerator();
  1707. currSetIL.Emit(OpCodes.Ldarg_0);
  1708. currSetIL.Emit(OpCodes.Ldarg_1);
  1709. currSetIL.Emit(OpCodes.Stfld, field);
  1710. currSetIL.Emit(OpCodes.Ret);
  1711. property.SetGetMethod(currGetPropMthdBldr);
  1712. property.SetSetMethod(currSetPropMthdBldr);
  1713. var getMethod = typeof(SqlMapperExtensions.IProxy).GetMethod("get_" + "IsDirty");
  1714. var setMethod = typeof(SqlMapperExtensions.IProxy).GetMethod("set_" + "IsDirty");
  1715. typeBuilder.DefineMethodOverride(currGetPropMthdBldr, getMethod);
  1716. typeBuilder.DefineMethodOverride(currSetPropMthdBldr, setMethod);
  1717. return currSetPropMthdBldr;
  1718. }
  1719. private static void CreateProperty<T>(TypeBuilder typeBuilder, string propertyName, Type propType, MethodInfo setIsDirtyMethod, bool isIdentity)
  1720. {
  1721. //Define the field and the property
  1722. var field = typeBuilder.DefineField("_" + propertyName, propType, FieldAttributes.Private);
  1723. var property = typeBuilder.DefineProperty(propertyName,
  1724. System.Reflection.PropertyAttributes.None,
  1725. propType,
  1726. new Type[] { propType });
  1727. const MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.Virtual |
  1728. MethodAttributes.HideBySig;
  1729. // Define the "get" and "set" accessor methods
  1730. var currGetPropMthdBldr = typeBuilder.DefineMethod("get_" + propertyName,
  1731. getSetAttr,
  1732. propType,
  1733. Type.EmptyTypes);
  1734. var currGetIL = currGetPropMthdBldr.GetILGenerator();
  1735. currGetIL.Emit(OpCodes.Ldarg_0);
  1736. currGetIL.Emit(OpCodes.Ldfld, field);
  1737. currGetIL.Emit(OpCodes.Ret);
  1738. var currSetPropMthdBldr = typeBuilder.DefineMethod("set_" + propertyName,
  1739. getSetAttr,
  1740. null,
  1741. new Type[] { propType });
  1742. //store value in private field and set the isdirty flag
  1743. var currSetIL = currSetPropMthdBldr.GetILGenerator();
  1744. currSetIL.Emit(OpCodes.Ldarg_0);
  1745. currSetIL.Emit(OpCodes.Ldarg_1);
  1746. currSetIL.Emit(OpCodes.Stfld, field);
  1747. currSetIL.Emit(OpCodes.Ldarg_0);
  1748. currSetIL.Emit(OpCodes.Ldc_I4_1);
  1749. currSetIL.Emit(OpCodes.Call, setIsDirtyMethod);
  1750. currSetIL.Emit(OpCodes.Ret);
  1751. //TODO: Should copy all attributes defined by the interface?
  1752. if (isIdentity)
  1753. {
  1754. var keyAttribute = typeof(KeyAttribute);
  1755. var myConstructorInfo = keyAttribute.GetConstructor(new Type[] { });
  1756. var attributeBuilder = new CustomAttributeBuilder(myConstructorInfo, new object[] { });
  1757. property.SetCustomAttribute(attributeBuilder);
  1758. }
  1759. property.SetGetMethod(currGetPropMthdBldr);
  1760. property.SetSetMethod(currSetPropMthdBldr);
  1761. var getMethod = typeof(T).GetMethod("get_" + propertyName);
  1762. var setMethod = typeof(T).GetMethod("set_" + propertyName);
  1763. typeBuilder.DefineMethodOverride(currGetPropMthdBldr, getMethod);
  1764. typeBuilder.DefineMethodOverride(currSetPropMthdBldr, setMethod);
  1765. }
  1766. }
  1767. }
  1768. [AttributeUsage(AttributeTargets.Class)]
  1769. public class TableAttribute : Attribute
  1770. {
  1771. public TableAttribute(string tableName)
  1772. {
  1773. Name = tableName;
  1774. }
  1775. public string Name { get; private set; }
  1776. }
  1777. }