SqlMapperExtensions.cs 87 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998
  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. var computedProperties = ComputedPropertiesCache(type);
  812. for (var i = 0; i < allProperties.Count(); i++)
  813. {
  814. var property = allProperties.ElementAt(i);
  815. if (keyProperties.Contains(property) || computedProperties.Contains(property))
  816. {
  817. continue;
  818. }
  819. sb.Append("[{0}]".Formater(property.Name));
  820. if (i < allProperties.Count() - 1)
  821. sb.Append(", ");
  822. }
  823. sb.Append(") values (");
  824. for (var i = 0; i < allProperties.Count(); i++)
  825. {
  826. var property = allProperties.ElementAt(i);
  827. if (keyProperties.Contains(property) || computedProperties.Contains(property))
  828. {
  829. continue;
  830. }
  831. //if (property.Name.ToLower() == "createtime" || property.Name.ToLower() == "updatetime")
  832. //{
  833. // property.SetValue(entityToInsert, DateTime.Now);
  834. //}
  835. //else if (property.Name.ToLower() == "createusername" || property.Name.ToLower() == "updateusername")
  836. //{
  837. // if (!string.IsNullOrWhiteSpace(unitOfWork.CurrentName))
  838. // {
  839. // property.SetValue(entityToInsert, unitOfWork.CurrentName);
  840. // }
  841. //}
  842. //else if (property.Name.ToLower() == "userid")
  843. //{
  844. // if (unitOfWork.CurrentId.HasValue)
  845. // {
  846. // property.SetValue(entityToInsert, unitOfWork.CurrentId.Value);
  847. // }
  848. //}
  849. sb.AppendFormat("@{0}", property.Name);
  850. if (i < allProperties.Count() - 1)
  851. sb.Append(", ");
  852. }
  853. sb.Append(") ");
  854. unitOfWork.Connection.Execute(sb.ToString(), entityToInsert, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout);
  855. }
  856. /// <summary>
  857. /// 非自增表的插入
  858. /// </summary>
  859. /// <typeparam name="T"></typeparam>
  860. /// <param name="unitOfWork"></param>
  861. /// <param name="entityToInsert"></param>
  862. /// <param name="commandTimeout"></param>
  863. public static async Task<bool> InsertNotIdentityAsync<T>(this IUnitOfWork unitOfWork, T entityToInsert, int? commandTimeout = null) where T : class
  864. {
  865. //using (var tx = connection.BeginTransaction())
  866. //{
  867. var type = typeof(T);
  868. var name = GetTableName(type);
  869. var sb = new StringBuilder(null);
  870. sb.AppendFormat("insert into {0} (", name);
  871. var allProperties = TypePropertiesCache(type);
  872. var keyProperties = KeyPropertiesCache(type);
  873. for (var i = 0; i < allProperties.Count(); i++)
  874. {
  875. var property = allProperties.ElementAt(i);
  876. var notIdentity = property.GetCustomAttribute<NotIdentityAttribute>();
  877. if (notIdentity == null && keyProperties.Contains(property))
  878. {
  879. continue;
  880. }
  881. sb.Append("[{0}]".Formater(property.Name));
  882. if (i < allProperties.Count() - 1)
  883. sb.Append(", ");
  884. }
  885. sb.Append(") values (");
  886. for (var i = 0; i < allProperties.Count(); i++)
  887. {
  888. var property = allProperties.ElementAt(i);
  889. var Identity = property.GetCustomAttribute<NotIdentityAttribute>();
  890. //不包含自增属性并且是主键
  891. if (Identity == null && keyProperties.Contains(property))
  892. {
  893. continue;
  894. }
  895. if (property.Name.ToLower() == "createtime" || property.Name.ToLower() == "updatetime")
  896. {
  897. property.SetValue(entityToInsert, DateTime.Now);
  898. }
  899. else if (property.Name.ToLower() == "createusername" || property.Name.ToLower() == "updateusername")
  900. {
  901. if (!string.IsNullOrWhiteSpace(unitOfWork.CurrentName))
  902. {
  903. property.SetValue(entityToInsert, unitOfWork.CurrentName);
  904. }
  905. }
  906. sb.AppendFormat("@{0}", property.Name);
  907. if (i < allProperties.Count() - 1)
  908. sb.Append(", ");
  909. }
  910. sb.Append(") ");
  911. #if DEBUG
  912. Trace.WriteLine(sb.ToString());
  913. #endif
  914. await unitOfWork.Connection.ExecuteAsync(sb.ToString(), entityToInsert, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout);
  915. return true;
  916. }
  917. /// <summary>
  918. /// 向没有主键、非自增表插入数据
  919. /// </summary>
  920. /// <typeparam name="T"></typeparam>
  921. /// <param name="unitOfWork"></param>
  922. /// <param name="entityToInsert"></param>
  923. /// <param name="commandTimeout"></param>
  924. public static async Task<bool> InsertOperateLogAsync<T>(this IUnitOfWork unitOfWork, T entityToInsert, int? commandTimeout = null) where T : class
  925. {
  926. var type = typeof(T);
  927. var name = GetTableName(type);
  928. var sb = new StringBuilder(null);
  929. sb.AppendFormat("insert into {0} (", name);
  930. var allProperties = TypePropertiesCache(type);
  931. var keyProperties = KeyPropertiesCache(type);
  932. for (var i = 0; i < allProperties.Count(); i++)
  933. {
  934. var property = allProperties.ElementAt(i);
  935. var notIdentity = property.GetCustomAttribute<NotIdentityAttribute>();
  936. //if (notIdentity == null && keyProperties.Contains(property))
  937. //{
  938. // continue;
  939. //}
  940. sb.Append("[{0}]".Formater(property.Name));
  941. if (i < allProperties.Count() - 1)
  942. sb.Append(", ");
  943. }
  944. sb.Append(") values (");
  945. for (var i = 0; i < allProperties.Count(); i++)
  946. {
  947. var property = allProperties.ElementAt(i);
  948. var Identity = property.GetCustomAttribute<NotIdentityAttribute>();
  949. //不包含自增属性并且是主键
  950. //if (Identity == null && keyProperties.Contains(property))
  951. //{
  952. // continue;
  953. //}
  954. if (property.Name.ToLower() == "createtime" || property.Name.ToLower() == "updatetime")
  955. {
  956. property.SetValue(entityToInsert, DateTime.Now);
  957. }
  958. else if (property.Name.ToLower() == "createusername" || property.Name.ToLower() == "updateusername")
  959. {
  960. if (!string.IsNullOrWhiteSpace(unitOfWork.CurrentName))
  961. {
  962. property.SetValue(entityToInsert, unitOfWork.CurrentName);
  963. }
  964. }
  965. sb.AppendFormat("@{0}", property.Name);
  966. if (i < allProperties.Count() - 1)
  967. sb.Append(", ");
  968. }
  969. sb.Append(") ");
  970. #if DEBUG
  971. Trace.WriteLine(sb.ToString());
  972. #endif
  973. await unitOfWork.Connection.ExecuteAsync(sb.ToString(), entityToInsert, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout);
  974. return true;
  975. }
  976. /// <summary>
  977. /// 根据某个字段修改表数据
  978. /// </summary>
  979. /// <typeparam name="T"></typeparam>
  980. /// <param name="unitOfWork"></param>
  981. /// <param name="field"></param>
  982. /// <param name="value"></param>
  983. /// <param name="pk"></param>
  984. /// <returns></returns>
  985. public static async Task<bool> UpdateByPrimaryKeyAsync<T>(this IUnitOfWork unitOfWork, string field, object value, int pk) where T : class
  986. {
  987. var type = typeof(T);
  988. await OperateLog<T>(unitOfWork, field, value, pk, type);
  989. var tableName = GetTableName(type);
  990. string where = @" where id=@id";
  991. string sql = "update {0} set {1} = @value,UpdateTime=@updateTime,UpdateUserName=@updateUserName".Formater(tableName, field);
  992. if (pk != 0)
  993. {
  994. sql += where;
  995. }
  996. else
  997. {
  998. throw new Exception("未传入正确的主键");
  999. }
  1000. #if DEBUG
  1001. Trace.WriteLine(sql);
  1002. #endif
  1003. var r = await unitOfWork.Connection.ExecuteAsync(sql, new { value = value, id = pk, updateTime = DateTime.Now, updateUserName = unitOfWork.CurrentName }, transaction: unitOfWork.Transaction, commandType: null);
  1004. return r > 0 ? true : false;
  1005. }
  1006. private static async Task<bool> OperateLog<T>(IUnitOfWork unitOfWork, string field, object value, int pk, Type type, DateTime? createTime = null) where T : class
  1007. {
  1008. if (createTime == null)
  1009. createTime = DateTime.Now;
  1010. var allProperties = TypePropertiesCache(type);
  1011. string logTableName = string.Empty;
  1012. string description = string.Empty;
  1013. bool isTrack = false;
  1014. var newValue = value;
  1015. var propertyValue = value;
  1016. foreach (var item in allProperties)
  1017. {
  1018. if (!item.Name.Equals(field, StringComparison.OrdinalIgnoreCase))
  1019. continue;
  1020. var track = item.GetCustomAttribute<TrackAttribute>();
  1021. if (track == null)
  1022. continue;
  1023. isTrack = true;
  1024. description = track.Description;
  1025. if (item.PropertyType.IsEnum && value.GetType().Equals(typeof(int)))
  1026. {
  1027. newValue = item.PropertyType.GetEnumName(value.ToString().TryConvertInt32());
  1028. propertyValue = item.PropertyType.GetField(newValue.ToString()).GetValue(null);
  1029. }
  1030. else if (item.PropertyType.IsEnum)
  1031. {
  1032. newValue = value.ToString();
  1033. propertyValue = item.PropertyType.GetField(value.ToString()).GetValue(null);
  1034. }
  1035. break;
  1036. }
  1037. if (isTrack)
  1038. {
  1039. var trackTable = type.GetCustomAttribute<TrackTableAttribute>();
  1040. var orign = await unitOfWork.GetAsync<T>(pk);
  1041. var orignType = orign.GetType();
  1042. if (
  1043. orignType.GetProperty(field) != null && (
  1044. (orignType.GetProperty(field).GetValue(orign) != null && orignType.GetProperty(field).GetValue(orign).Equals(propertyValue))
  1045. ||
  1046. (orignType.GetProperty(field).GetValue(orign) == null && propertyValue == null))
  1047. )
  1048. {
  1049. return false;
  1050. }
  1051. if (trackTable == null)
  1052. throw new Exception("TrackTable未设定,请检查实体类");
  1053. logTableName = GetTableName(trackTable.Table);
  1054. var allLogProperties = TypePropertiesCache(trackTable.Table);
  1055. StringBuilder sb = new StringBuilder();
  1056. sb.AppendFormat("insert into {0}", logTableName);
  1057. sb.Append("(");
  1058. for (var i = 0; i < allLogProperties.Count(); i++)
  1059. {
  1060. var property = allLogProperties.ElementAt(i);
  1061. sb.Append(property.Name);
  1062. if (i < allLogProperties.Count() - 1)
  1063. sb.Append(", ");
  1064. }
  1065. sb.Append(")");
  1066. sb.Append("values");
  1067. sb.Append("(");
  1068. for (var i = 0; i < allLogProperties.Count(); i++)
  1069. {
  1070. var property = allLogProperties.ElementAt(i);
  1071. sb.AppendFormat("@{0}", property.Name);
  1072. if (i < allLogProperties.Count() - 1)
  1073. sb.Append(", ");
  1074. }
  1075. sb.Append(")");
  1076. var instance = Activator.CreateInstance(trackTable.Table);
  1077. var properties = instance.GetType().GetProperties().Where(p => p.PropertyType.IsPublic && p.CanWrite).ToList();
  1078. foreach (var item in properties)
  1079. {
  1080. switch (item.Name.ToLower())
  1081. {
  1082. case "id":
  1083. item.SetValue(instance, pk);
  1084. break;
  1085. case "field":
  1086. item.SetValue(instance, field);
  1087. break;
  1088. case "fielddesc":
  1089. item.SetValue(instance, description);
  1090. break;
  1091. case "oldvalue":
  1092. var result = orignType.GetProperty(field).GetValue(orign) ?? orignType.GetProperty(field);
  1093. item.SetValue(instance, result == null ? "" : result.ToString());
  1094. break;
  1095. case "newvalue":
  1096. item.SetValue(instance, newValue == null ? "" : newValue.ToString());
  1097. break;
  1098. case "createtime":
  1099. item.SetValue(instance, createTime.Value);
  1100. break;
  1101. case "createusername":
  1102. item.SetValue(instance, string.IsNullOrWhiteSpace(unitOfWork.CurrentName) ? "System" : unitOfWork.CurrentName);
  1103. break;
  1104. case "updatetime":
  1105. item.SetValue(instance, DateTime.Now);
  1106. break;
  1107. case "updateusername":
  1108. item.SetValue(instance, string.IsNullOrWhiteSpace(unitOfWork.CurrentName) ? "System" : unitOfWork.CurrentName);
  1109. break;
  1110. }
  1111. }
  1112. #if DEBUG
  1113. Trace.WriteLine(sb.ToString());
  1114. #endif
  1115. await unitOfWork.Connection.ExecuteAsync(sb.ToString(), instance, transaction: unitOfWork.Transaction, commandType: null);
  1116. }
  1117. return true;
  1118. }
  1119. public static async Task<bool> UpdateByPrimaryKeyAsync<T, TProperty>(this IUnitOfWork unitOfWork, Expression<Func<T, TProperty>> expression, int id, object value) where T : class
  1120. {
  1121. var type = typeof(T);
  1122. string field = (expression.Body as System.Linq.Expressions.MemberExpression).Member.Name;
  1123. await OperateLog<T>(unitOfWork, field, value, id, type);
  1124. var tableName = GetTableName(type);
  1125. string sql = "update {0} set {1} = @value,UpdateTime=@updateTime,UpdateUserName=@updateUserName where id=@id".Formater(tableName, field);
  1126. #if DEBUG
  1127. Trace.WriteLine(sql);
  1128. #endif
  1129. var o = await unitOfWork.Connection.ExecuteAsync(sql, new { value = value, id = id, updateTime = DateTime.Now, updateUserName = unitOfWork.CurrentName }, transaction: unitOfWork.Transaction, commandType: null);
  1130. return o > 0 ? true : false;
  1131. }
  1132. public static async Task<bool> UpdateByConditionAsync<T, TProperty>(this IUnitOfWork unitOfWork, Expression<Func<T, TProperty>> expression, string[] propertys, object[] values) where T : class
  1133. {
  1134. var type = typeof(T);
  1135. var set = string.Empty;
  1136. var dic = new Dictionary<string, object>();
  1137. for (int i = 0; i < propertys.Length; i++)
  1138. {
  1139. set += propertys[i] + "=@" + propertys[i] + ",";
  1140. dic.Add("@" + propertys[i], values[i]);
  1141. }
  1142. dic.Add("@updateTime", DateTime.Now);
  1143. dic.Add("@updateUserName", unitOfWork.CurrentName);
  1144. var tableName = GetTableName(type);
  1145. var translator = new QueryTranslator();
  1146. var where = translator.Translate(expression);
  1147. var sql = "update {0} set {1} UpdateTime=@updateTime,UpdateUserName=@updateUserName {2}".Formater(tableName, set, string.IsNullOrEmpty(where.Trim()) ? string.Empty : " where " + where);
  1148. #if DEBUG
  1149. Trace.WriteLine(sql);
  1150. #endif
  1151. var r = await unitOfWork.Connection.ExecuteAsync(sql, dic, transaction: unitOfWork.Transaction, commandType: null);
  1152. return r > 0 ? true : false;
  1153. }
  1154. public static async Task<bool> UpdateByConditionAsync<T, TProperty>(this IUnitOfWork unitOfWork, Expression<Func<T, TProperty>> expression, object t) where T : class
  1155. {
  1156. var type = typeof(T);
  1157. var psc = type.GetProperties();
  1158. var ps = t.GetType().GetProperties();
  1159. var set = string.Empty;
  1160. var tableName = GetTableName(type);
  1161. foreach (var item in ps)
  1162. {
  1163. if (psc.Where(x => x.Name.Equals(item.Name, StringComparison.OrdinalIgnoreCase)).Count() <= 0)
  1164. throw new Exception(string.Format("表{0}中不存在字段{1}", tableName, item.Name));
  1165. set += item.Name + "=@" + item.Name + ",";
  1166. }
  1167. var translator = new QueryTranslator();
  1168. var where = translator.Translate(expression);
  1169. var sql = "update {0} set {1} UpdateTime='{3}',UpdateUserName='{4}' {2}".Formater(
  1170. tableName,
  1171. set,
  1172. string.IsNullOrEmpty(where.Trim()) ? string.Empty : " where " + where,
  1173. DateTime.Now,
  1174. unitOfWork.CurrentName);
  1175. #if DEBUG
  1176. Trace.WriteLine(sql);
  1177. #endif
  1178. var r = await unitOfWork.Connection.ExecuteAsync(sql, t, transaction: unitOfWork.Transaction, commandType: null);
  1179. return r > 0 ? true : false;
  1180. }
  1181. public static async Task<bool> UpdateByConditionAsync<T, TProperty>(this IUnitOfWork unitOfWork, Expression<Func<T, TProperty>> expression, string sql) where T : class
  1182. {
  1183. var type = typeof(T);
  1184. var psc = type.GetProperties();
  1185. var tableName = GetTableName(type);
  1186. var where = string.Empty;
  1187. if (expression != null)
  1188. {
  1189. var translator = new QueryTranslator();
  1190. where = translator.Translate(expression);
  1191. }
  1192. if (!string.IsNullOrEmpty(where.Trim()))
  1193. {
  1194. if (sql.ToLower().Contains("where"))
  1195. {
  1196. sql += where;
  1197. }
  1198. else
  1199. {
  1200. sql += " where " + where;
  1201. }
  1202. }
  1203. #if DEBUG
  1204. Trace.WriteLine(sql);
  1205. #endif
  1206. var obj = await unitOfWork.Connection.ExecuteAsync(sql, new { }, transaction: unitOfWork.Transaction, commandType: null);
  1207. return obj > 0 ? true : false;
  1208. }
  1209. public static async Task<int> CountAsync<T>(this IUnitOfWork unitOfWork, Expression<Func<T, bool>> expression, QueryModel model, int? commandTimeout = null) where T : class
  1210. {
  1211. var type = typeof(T);
  1212. string sql;
  1213. var name = GetTableName(type);
  1214. sql = "select count(0) from " + name + " (NOLOCK) where 1=1 {0}";
  1215. var translator = new QueryTranslator();
  1216. string where = translator.Translate(expression);
  1217. sql = string.Format(sql, string.IsNullOrEmpty(where) ? "" : (" and " + where));
  1218. if (model != null && model.DataPermission != null && model.DataPermission.Count > 0)
  1219. {
  1220. //存在数据权限
  1221. var allProperties = TypePropertiesCache(typeof(T));
  1222. for (var i = 0; i < allProperties.Count(); i++)
  1223. {
  1224. var property = allProperties.ElementAt(i);
  1225. var identity = property.GetCustomAttribute<DataPermissionAttribute>();
  1226. if (identity == null)
  1227. continue;
  1228. var permission = model.DataPermission.Find(x => x.PermissioinType == identity.PermissionType.GetValue());
  1229. if (permission == null)
  1230. continue;
  1231. if (string.IsNullOrWhiteSpace(permission.Value))
  1232. continue;
  1233. sql += " AND {0} IN ({1})".Formater(property.Name, permission.Value.TrimEnd(','));
  1234. }
  1235. }
  1236. #if DEBUG
  1237. Trace.WriteLine(sql);
  1238. #endif
  1239. return await unitOfWork.Connection.ExecuteScalarAsync<int>(sql, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout);
  1240. }
  1241. 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
  1242. {
  1243. string field = (propName.Body as System.Linq.Expressions.MemberExpression).Member.Name;
  1244. var name = GetTableName(typeof(T));
  1245. string sql = string.Format(" SELECT {1} AS [Status] , COUNT(0) AS [Count] FROM {0} (NOLOCK) ", name, field);
  1246. sql += " where 1=1 ";
  1247. if (expression != null)
  1248. {
  1249. var translator = new QueryTranslator();
  1250. var where = translator.Translate(expression);
  1251. sql += string.IsNullOrEmpty(where.Trim()) ? string.Empty : " and " + where;
  1252. }
  1253. if (unitOfWork.DataPermission != null && unitOfWork.DataPermission.Count > 0)
  1254. {//存在数据权限
  1255. var allProperties = TypePropertiesCache(typeof(T));
  1256. for (var i = 0; i < allProperties.Count(); i++)
  1257. {
  1258. var property = allProperties.ElementAt(i);
  1259. var identity = property.GetCustomAttribute<DataPermissionAttribute>();
  1260. if (identity == null)
  1261. continue;
  1262. var permission = unitOfWork.DataPermission.Find(x => x.PermissioinType == identity.PermissionType.GetValue());
  1263. if (permission == null)
  1264. continue;
  1265. if (string.IsNullOrWhiteSpace(permission.Value))
  1266. continue;
  1267. sql += " AND {0} IN ({1})".Formater(property.Name, permission.Value.TrimEnd(','));
  1268. }
  1269. }
  1270. sql += string.Format(" GROUP BY {0} ", field);
  1271. #if DEBUG
  1272. Trace.WriteLine(sql);
  1273. #endif
  1274. var result = await unitOfWork.Connection.QueryAsync<dynamic>(sql, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout);
  1275. IDictionary<int, int> dic = new Dictionary<int, int>();
  1276. foreach (var item in result)
  1277. {
  1278. dic.Add(item.Status, item.Count);
  1279. }
  1280. return dic;
  1281. }
  1282. public static async Task<bool> UpdateListAsync<T>(this IUnitOfWork unitOfWork, IList<T> list, int? commandTimeout = null) where T : class
  1283. {
  1284. if (list.Count == 0)
  1285. return false;
  1286. var proxy = list.First() as IProxy;
  1287. if (proxy != null)
  1288. {
  1289. if (!proxy.IsDirty) return false;
  1290. }
  1291. var type = typeof(T);
  1292. var keyProperties = KeyPropertiesCache(type);
  1293. if (keyProperties.Count() == 0)
  1294. throw new ArgumentException("实体必须包含一个主键 [Key] 属性");
  1295. var key = keyProperties.FirstOrDefault();
  1296. var name = GetTableName(type);
  1297. var allProperties = TypePropertiesCache(type);
  1298. var nonIdProps = allProperties.Where(a => !keyProperties.Contains(a));
  1299. var sb = new StringBuilder();
  1300. foreach (var entityToUpdate in list)
  1301. {
  1302. sb.Append("update {0} set ".Formater(name));
  1303. for (var i = 0; i < nonIdProps.Count(); i++)
  1304. {
  1305. var property = nonIdProps.ElementAt(i);
  1306. var value = property.GetValue(entityToUpdate);
  1307. if (property.Name.ToLower() == "createtime" || property.Name.ToLower() == "createusername")
  1308. continue;
  1309. if (property.Name.ToLower() == "updatetime")
  1310. {
  1311. property.SetValue(entityToUpdate, DateTime.Now);
  1312. }
  1313. else if (property.Name.ToLower() == "updateusername" || property.Name.ToLower() == "shelvesusername")// || property.Name.ToLower() == "allottedusername")
  1314. {
  1315. if (!string.IsNullOrWhiteSpace(unitOfWork.CurrentName))
  1316. {
  1317. property.SetValue(entityToUpdate, unitOfWork.CurrentName);
  1318. }
  1319. }
  1320. //add gyp 20160608 非ERP操作的(例:PDA)动态设置值
  1321. else if (property.Name.ToLower() == "userid" || property.Name.ToLower() == "shelvesuserid")// || property.Name.ToLower() == "allotteduserid")
  1322. {
  1323. if (unitOfWork.CurrentId.HasValue)
  1324. {
  1325. property.SetValue(entityToUpdate, unitOfWork.CurrentId.Value);
  1326. }
  1327. }
  1328. if (property.GetValue(entityToUpdate) == null)
  1329. {
  1330. sb.AppendFormat("[{0}] = null", property.Name, property.GetValue(entityToUpdate));
  1331. }
  1332. else if (property.PropertyType == typeof(string) || property.PropertyType == typeof(DateTime) || property.PropertyType == typeof(DateTime?))
  1333. {
  1334. sb.AppendFormat("[{0}] = '{1}'", property.Name, property.GetValue(entityToUpdate).ToString().Replace("'", "''"));
  1335. }
  1336. else
  1337. {
  1338. sb.AppendFormat("[{0}] = {1}", property.Name, property.GetValue(entityToUpdate));
  1339. }
  1340. if (i < nonIdProps.Count() - 1)
  1341. sb.AppendFormat(", ");
  1342. }
  1343. sb.Append(" where ");
  1344. for (var i = 0; i < keyProperties.Count(); i++)
  1345. {
  1346. var property = keyProperties.ElementAt(i);
  1347. sb.AppendFormat("[{0}] = {1}", property.Name, property.GetValue(entityToUpdate));
  1348. if (i < keyProperties.Count() - 1)
  1349. sb.AppendFormat(" and ");
  1350. }
  1351. sb.AppendLine();
  1352. }
  1353. var updated = await unitOfWork.Connection.ExecuteAsync(sb.ToString(), null, commandTimeout: commandTimeout, transaction: unitOfWork.Transaction);
  1354. return updated > 0;
  1355. }
  1356. /// <summary>
  1357. /// Updates entity in table "Ts", checks if the entity is modified if the entity is tracked by the Get() extension.
  1358. /// </summary>
  1359. /// <typeparam name="T">Type to be updated</typeparam>
  1360. /// <param name="connection">Open SqlConnection</param>
  1361. /// <param name="entityToUpdate">Entity to be updated</param>
  1362. /// <returns>true if updated, false if not found or not modified (tracked entities)</returns>
  1363. public static async Task<bool> UpdateAsync<T>(this IUnitOfWork unitOfWork, T entityToUpdate, int? commandTimeout = null) where T : class
  1364. {
  1365. var proxy = entityToUpdate as IProxy;
  1366. if (proxy != null)
  1367. {
  1368. if (!proxy.IsDirty) return false;
  1369. }
  1370. var type = typeof(T);
  1371. var keyProperties = KeyPropertiesCache(type);
  1372. if (keyProperties.Count() == 0)
  1373. throw new ArgumentException("实体必须包含一个主键 [Key] 属性");
  1374. var key = keyProperties.FirstOrDefault();
  1375. var name = GetTableName(type);
  1376. var sb = new StringBuilder();
  1377. sb.AppendFormat("update {0} set ", name);
  1378. var allProperties = TypePropertiesCache(type);
  1379. var computedProperties = ComputedPropertiesCache(type);
  1380. var nonIdProps = allProperties.Where(a => !keyProperties.Contains(a) && !computedProperties.Contains(a));
  1381. DateTime operTime = DateTime.Now;
  1382. for (var i = 0; i < nonIdProps.Count(); i++)
  1383. {
  1384. var property = nonIdProps.ElementAt(i);
  1385. var value = property.GetValue(entityToUpdate);
  1386. if (property.Name.ToLower() == "createtime" || property.Name.ToLower() == "createusername")
  1387. continue;
  1388. if (property.Name.ToLower() == "updatetime")
  1389. {
  1390. property.SetValue(entityToUpdate, DateTime.Now);
  1391. }
  1392. else if (property.Name.ToLower() == "updateusername" || property.Name.ToLower() == "shelvesusername")// || property.Name.ToLower() == "allottedusername")
  1393. {
  1394. if (!string.IsNullOrWhiteSpace(unitOfWork.CurrentName))
  1395. {
  1396. property.SetValue(entityToUpdate, unitOfWork.CurrentName);
  1397. }
  1398. }
  1399. //add gyp 20160608 非ERP操作的(例:PDA)动态设置值
  1400. else if (property.Name.ToLower() == "userid" || property.Name.ToLower() == "shelvesuserid")// || property.Name.ToLower() == "allotteduserid")
  1401. {
  1402. if (unitOfWork.CurrentId.HasValue)
  1403. {
  1404. property.SetValue(entityToUpdate, unitOfWork.CurrentId.Value);
  1405. }
  1406. }
  1407. sb.AppendFormat("[{0}] = @{1}", property.Name, property.Name);
  1408. if (i < nonIdProps.Count() - 1)
  1409. sb.AppendFormat(", ");
  1410. await OperateLog<T>(unitOfWork, property.Name, value, key.GetValue(entityToUpdate).ToString().TryConvertInt32(), type, operTime);
  1411. }
  1412. sb.Append(" where ");
  1413. for (var i = 0; i < keyProperties.Count(); i++)
  1414. {
  1415. var property = keyProperties.ElementAt(i);
  1416. sb.AppendFormat("[{0}] = @{1}", property.Name, property.Name);
  1417. if (i < keyProperties.Count() - 1)
  1418. sb.AppendFormat(" and ");
  1419. }
  1420. #if DEBUG
  1421. Trace.WriteLine(sb.ToString());
  1422. #endif
  1423. var updated = await unitOfWork.Connection.ExecuteAsync(sb.ToString(), entityToUpdate, commandTimeout: commandTimeout, transaction: unitOfWork.Transaction);
  1424. return updated > 0;
  1425. }
  1426. /// <summary>
  1427. /// Delete entity in table "Ts".
  1428. /// </summary>
  1429. /// <typeparam name="T">Type of entity</typeparam>
  1430. /// <param name="connection">Open SqlConnection</param>
  1431. /// <param name="entityToDelete">Entity to delete</param>
  1432. /// <returns>true if deleted, false if not found</returns>
  1433. public static async Task<bool> DeleteAsync<T>(this IUnitOfWork unitOfWork, T entityToDelete, int? commandTimeout = null) where T : class
  1434. {
  1435. var type = typeof(T);
  1436. var keyProperties = KeyPropertiesCache(type);
  1437. if (keyProperties.Count() == 0)
  1438. throw new ArgumentException("实体必须包含一个主键 [Key] 属性");
  1439. var name = GetTableName(type);
  1440. var sb = new StringBuilder();
  1441. sb.AppendFormat("delete from {0} where ", name);
  1442. for (var i = 0; i < keyProperties.Count(); i++)
  1443. {
  1444. var property = keyProperties.ElementAt(i);
  1445. sb.AppendFormat("[{0}] = @{1}", property.Name, property.Name);
  1446. if (i < keyProperties.Count() - 1)
  1447. sb.AppendFormat(" and ");
  1448. }
  1449. #if DEBUG
  1450. Trace.WriteLine(sb.ToString());
  1451. #endif
  1452. var deleted = await unitOfWork.Connection.ExecuteAsync(sb.ToString(), entityToDelete, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout);
  1453. return deleted > 0;
  1454. }
  1455. public static async Task<bool> DeleteAsync<T>(this IUnitOfWork unitOfWork, List<T> list, int? commandTimeout = null) where T : class
  1456. {
  1457. var type = typeof(T);
  1458. var keyProperties = KeyPropertiesCache(type);
  1459. if (keyProperties.Count() == 0)
  1460. throw new ArgumentException("实体必须包含一个主键 [Key] 属性");
  1461. var name = GetTableName(type);
  1462. var sb = new StringBuilder();
  1463. sb.AppendFormat("delete from {0} where ", name);
  1464. for (var i = 0; i < keyProperties.Count(); i++)
  1465. {
  1466. var property = keyProperties.ElementAt(i);
  1467. sb.AppendFormat("[{0}] = @{1}", property.Name, property.Name);
  1468. if (i < keyProperties.Count() - 1)
  1469. sb.AppendFormat(" and ");
  1470. }
  1471. var deleted = 0;
  1472. foreach (var item in list)
  1473. {
  1474. #if DEBUG
  1475. Trace.WriteLine(sb.ToString());
  1476. #endif
  1477. deleted += await unitOfWork.Connection.ExecuteAsync(sb.ToString(), item, transaction: unitOfWork.Transaction, commandTimeout: commandTimeout);
  1478. }
  1479. return deleted > 0;
  1480. }
  1481. public static async Task<bool> DeleteByIdAsync<T>(this IUnitOfWork unitOfWork, int id) where T : class
  1482. {
  1483. var type = typeof(T);
  1484. var tableName = GetTableName(type);
  1485. string sql = "delete from {0} where id=@id".Formater(tableName);
  1486. #if DEBUG
  1487. Trace.WriteLine(sql);
  1488. #endif
  1489. var qty = await unitOfWork.Connection.ExecuteAsync(sql, new { id = id, updateTime = DateTime.Now, updateUserName = unitOfWork.CurrentName }, transaction: unitOfWork.Transaction, commandType: null);
  1490. return qty > 0 ? true : false;
  1491. }
  1492. public static void BulkToDB<T>(this SqlConnection conn, List<T> t, SqlTransaction tran)
  1493. {
  1494. var type = typeof(T);
  1495. var name = GetTableName(type);
  1496. var allProperties = TypePropertiesCache(type);
  1497. DataTable dt = new DataTable();
  1498. for (int i = 0; i < allProperties.Count(); i++)
  1499. {
  1500. var property = allProperties.ElementAt(i);
  1501. dt.Columns.Add(property.Name);
  1502. }
  1503. foreach (var item in t)
  1504. {
  1505. var itemType = item.GetType();
  1506. var properties = TypePropertiesCache(itemType);
  1507. DataRow dr = dt.NewRow();
  1508. for (int i = 0; i < properties.Count(); i++)
  1509. {
  1510. var property = properties.ElementAt(i);
  1511. if (property.Name.Equals("id", StringComparison.OrdinalIgnoreCase))
  1512. continue;
  1513. if (property.PropertyType.IsEnum)
  1514. {
  1515. //alter zkp 20160524
  1516. dr[property.Name] = Convert.ToInt32(property.GetValue(item));
  1517. }
  1518. else
  1519. {
  1520. dr[property.Name] = property.GetValue(item);
  1521. }
  1522. }
  1523. dt.Rows.Add(dr);
  1524. }
  1525. using (SqlBulkCopy bulkCopy = new SqlBulkCopy(conn, SqlBulkCopyOptions.Default, tran))
  1526. {
  1527. bulkCopy.DestinationTableName = name;
  1528. for (int i = 0; i < allProperties.Count(); i++)
  1529. {
  1530. var property = allProperties.ElementAt(i);
  1531. if (property.Name.Equals("id", StringComparison.OrdinalIgnoreCase))
  1532. continue;
  1533. bulkCopy.ColumnMappings.Add(property.Name, property.Name);
  1534. }
  1535. bulkCopy.BatchSize = t.Count;
  1536. bulkCopy.WriteToServer(dt);
  1537. }
  1538. }
  1539. public static void BulkToDB<T>(this SqlConnection conn, List<T> t)
  1540. {
  1541. var type = typeof(T);
  1542. var name = GetTableName(type);
  1543. var allProperties = TypePropertiesCache(type);
  1544. DataTable dt = new DataTable();
  1545. for (int i = 0; i < allProperties.Count(); i++)
  1546. {
  1547. var property = allProperties.ElementAt(i);
  1548. dt.Columns.Add(property.Name);
  1549. }
  1550. foreach (var item in t)
  1551. {
  1552. var itemType = item.GetType();
  1553. var properties = TypePropertiesCache(itemType);
  1554. DataRow dr = dt.NewRow();
  1555. for (int i = 0; i < properties.Count(); i++)
  1556. {
  1557. var property = properties.ElementAt(i);
  1558. if (property.Name.Equals("id", StringComparison.OrdinalIgnoreCase))
  1559. continue;
  1560. if (property.PropertyType.IsEnum)
  1561. {
  1562. //alter zkp 20160524
  1563. dr[property.Name] = Convert.ToInt32(property.GetValue(item));
  1564. }
  1565. else
  1566. {
  1567. dr[property.Name] = property.GetValue(item);
  1568. }
  1569. }
  1570. dt.Rows.Add(dr);
  1571. }
  1572. using (SqlBulkCopy bulkCopy = new SqlBulkCopy(conn, SqlBulkCopyOptions.Default, null))
  1573. {
  1574. bulkCopy.DestinationTableName = name;
  1575. for (int i = 0; i < allProperties.Count(); i++)
  1576. {
  1577. var property = allProperties.ElementAt(i);
  1578. if (property.Name.Equals("id", StringComparison.OrdinalIgnoreCase))
  1579. continue;
  1580. bulkCopy.ColumnMappings.Add(property.Name, property.Name);
  1581. }
  1582. bulkCopy.BatchSize = t.Count;
  1583. bulkCopy.WriteToServer(dt);
  1584. }
  1585. }
  1586. public static async Task<bool> BulkToDBAsync<T>(this IUnitOfWork unitOfWork, List<T> t)
  1587. {
  1588. var type = typeof(T);
  1589. var name = GetTableName(type);
  1590. var allProperties = TypePropertiesCache(type);
  1591. allProperties = allProperties.Where(p => !p.GetCustomAttributes(true).Any(a => a is NoDbAttribute)).ToList();
  1592. DataTable dt = new DataTable();
  1593. for (int i = 0; i < allProperties.Count(); i++)
  1594. {
  1595. var property = allProperties.ElementAt(i);
  1596. dt.Columns.Add(property.Name);
  1597. }
  1598. foreach (var item in t)
  1599. {
  1600. var itemType = item.GetType();
  1601. var properties = TypePropertiesCache(itemType);
  1602. properties = properties.Where(p => !p.GetCustomAttributes(true).Any(a => a is NoDbAttribute)).ToList();
  1603. DataRow dr = dt.NewRow();
  1604. for (int i = 0; i < properties.Count(); i++)
  1605. {
  1606. var property = properties.ElementAt(i);
  1607. if (property.Name.Equals("id", StringComparison.OrdinalIgnoreCase))
  1608. continue;
  1609. if (property.PropertyType.IsEnum)
  1610. {
  1611. //alter zkp 20160524
  1612. dr[property.Name] = Convert.ToInt32(property.GetValue(item));
  1613. }
  1614. else
  1615. {
  1616. dr[property.Name] = property.GetValue(item);
  1617. }
  1618. }
  1619. dt.Rows.Add(dr);
  1620. }
  1621. var connection = unitOfWork.Connection;
  1622. using (SqlBulkCopy bulkCopy = new SqlBulkCopy((SqlConnection)unitOfWork.Connection, SqlBulkCopyOptions.Default, (SqlTransaction)unitOfWork.Transaction))
  1623. {
  1624. if (connection.State == ConnectionState.Closed)
  1625. connection.Open();
  1626. bulkCopy.DestinationTableName = name;
  1627. for (int i = 0; i < allProperties.Count(); i++)
  1628. {
  1629. var property = allProperties.ElementAt(i);
  1630. if (property.Name.Equals("id", StringComparison.OrdinalIgnoreCase))
  1631. continue;
  1632. bulkCopy.ColumnMappings.Add(property.Name, property.Name);
  1633. }
  1634. bulkCopy.BatchSize = t.Count;
  1635. bulkCopy.BulkCopyTimeout = 120;
  1636. await bulkCopy.WriteToServerAsync(dt);
  1637. //unitOfWork.Connection.Close();
  1638. }
  1639. return true;
  1640. }
  1641. class ProxyGenerator
  1642. {
  1643. private static readonly Dictionary<Type, object> TypeCache = new Dictionary<Type, object>();
  1644. private static AssemblyBuilder GetAsmBuilder(string name)
  1645. {
  1646. var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName { Name = name },
  1647. AssemblyBuilderAccess.Run); //NOTE: to save, use RunAndSave
  1648. return assemblyBuilder;
  1649. }
  1650. public static T GetClassProxy<T>()
  1651. {
  1652. // A class proxy could be implemented if all properties are virtual
  1653. // otherwise there is a pretty dangerous case where internal actions will not update dirty tracking
  1654. throw new NotImplementedException();
  1655. }
  1656. public static T GetInterfaceProxy<T>()
  1657. {
  1658. Type typeOfT = typeof(T);
  1659. if (TypeCache.ContainsKey(typeOfT))
  1660. {
  1661. return (T)TypeCache[typeOfT];
  1662. }
  1663. var assemblyBuilder = GetAsmBuilder(typeOfT.Name);
  1664. var moduleBuilder = assemblyBuilder.DefineDynamicModule("SqlMapperExtensions." + typeOfT.Name); //NOTE: to save, add "asdasd.dll" parameter
  1665. var interfaceType = typeof(SqlMapperExtensions.IProxy);
  1666. var typeBuilder = moduleBuilder.DefineType(typeOfT.Name + "_" + Guid.NewGuid(),
  1667. TypeAttributes.Public | TypeAttributes.Class);
  1668. typeBuilder.AddInterfaceImplementation(typeOfT);
  1669. typeBuilder.AddInterfaceImplementation(interfaceType);
  1670. //create our _isDirty field, which implements IProxy
  1671. var setIsDirtyMethod = CreateIsDirtyProperty(typeBuilder);
  1672. // Generate a field for each property, which implements the T
  1673. foreach (var property in typeof(T).GetProperties())
  1674. {
  1675. var isId = property.GetCustomAttributes(true).Any(a => a is KeyAttribute);
  1676. CreateProperty<T>(typeBuilder, property.Name, property.PropertyType, setIsDirtyMethod, isId);
  1677. }
  1678. var generatedType = typeBuilder.CreateTypeInfo().AsType();
  1679. //assemblyBuilder.Save(name + ".dll"); //NOTE: to save, uncomment
  1680. var generatedObject = Activator.CreateInstance(generatedType);
  1681. TypeCache.Add(typeOfT, generatedObject);
  1682. return (T)generatedObject;
  1683. }
  1684. private static MethodInfo CreateIsDirtyProperty(TypeBuilder typeBuilder)
  1685. {
  1686. var propType = typeof(bool);
  1687. var field = typeBuilder.DefineField("_" + "IsDirty", propType, FieldAttributes.Private);
  1688. var property = typeBuilder.DefineProperty("IsDirty",
  1689. System.Reflection.PropertyAttributes.None,
  1690. propType,
  1691. new Type[] { propType });
  1692. const MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.NewSlot | MethodAttributes.SpecialName |
  1693. MethodAttributes.Final | MethodAttributes.Virtual | MethodAttributes.HideBySig;
  1694. // Define the "get" and "set" accessor methods
  1695. var currGetPropMthdBldr = typeBuilder.DefineMethod("get_" + "IsDirty",
  1696. getSetAttr,
  1697. propType,
  1698. Type.EmptyTypes);
  1699. var currGetIL = currGetPropMthdBldr.GetILGenerator();
  1700. currGetIL.Emit(OpCodes.Ldarg_0);
  1701. currGetIL.Emit(OpCodes.Ldfld, field);
  1702. currGetIL.Emit(OpCodes.Ret);
  1703. var currSetPropMthdBldr = typeBuilder.DefineMethod("set_" + "IsDirty",
  1704. getSetAttr,
  1705. null,
  1706. new Type[] { propType });
  1707. var currSetIL = currSetPropMthdBldr.GetILGenerator();
  1708. currSetIL.Emit(OpCodes.Ldarg_0);
  1709. currSetIL.Emit(OpCodes.Ldarg_1);
  1710. currSetIL.Emit(OpCodes.Stfld, field);
  1711. currSetIL.Emit(OpCodes.Ret);
  1712. property.SetGetMethod(currGetPropMthdBldr);
  1713. property.SetSetMethod(currSetPropMthdBldr);
  1714. var getMethod = typeof(SqlMapperExtensions.IProxy).GetMethod("get_" + "IsDirty");
  1715. var setMethod = typeof(SqlMapperExtensions.IProxy).GetMethod("set_" + "IsDirty");
  1716. typeBuilder.DefineMethodOverride(currGetPropMthdBldr, getMethod);
  1717. typeBuilder.DefineMethodOverride(currSetPropMthdBldr, setMethod);
  1718. return currSetPropMthdBldr;
  1719. }
  1720. private static void CreateProperty<T>(TypeBuilder typeBuilder, string propertyName, Type propType, MethodInfo setIsDirtyMethod, bool isIdentity)
  1721. {
  1722. //Define the field and the property
  1723. var field = typeBuilder.DefineField("_" + propertyName, propType, FieldAttributes.Private);
  1724. var property = typeBuilder.DefineProperty(propertyName,
  1725. System.Reflection.PropertyAttributes.None,
  1726. propType,
  1727. new Type[] { propType });
  1728. const MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.Virtual |
  1729. MethodAttributes.HideBySig;
  1730. // Define the "get" and "set" accessor methods
  1731. var currGetPropMthdBldr = typeBuilder.DefineMethod("get_" + propertyName,
  1732. getSetAttr,
  1733. propType,
  1734. Type.EmptyTypes);
  1735. var currGetIL = currGetPropMthdBldr.GetILGenerator();
  1736. currGetIL.Emit(OpCodes.Ldarg_0);
  1737. currGetIL.Emit(OpCodes.Ldfld, field);
  1738. currGetIL.Emit(OpCodes.Ret);
  1739. var currSetPropMthdBldr = typeBuilder.DefineMethod("set_" + propertyName,
  1740. getSetAttr,
  1741. null,
  1742. new Type[] { propType });
  1743. //store value in private field and set the isdirty flag
  1744. var currSetIL = currSetPropMthdBldr.GetILGenerator();
  1745. currSetIL.Emit(OpCodes.Ldarg_0);
  1746. currSetIL.Emit(OpCodes.Ldarg_1);
  1747. currSetIL.Emit(OpCodes.Stfld, field);
  1748. currSetIL.Emit(OpCodes.Ldarg_0);
  1749. currSetIL.Emit(OpCodes.Ldc_I4_1);
  1750. currSetIL.Emit(OpCodes.Call, setIsDirtyMethod);
  1751. currSetIL.Emit(OpCodes.Ret);
  1752. //TODO: Should copy all attributes defined by the interface?
  1753. if (isIdentity)
  1754. {
  1755. var keyAttribute = typeof(KeyAttribute);
  1756. var myConstructorInfo = keyAttribute.GetConstructor(new Type[] { });
  1757. var attributeBuilder = new CustomAttributeBuilder(myConstructorInfo, new object[] { });
  1758. property.SetCustomAttribute(attributeBuilder);
  1759. }
  1760. property.SetGetMethod(currGetPropMthdBldr);
  1761. property.SetSetMethod(currSetPropMthdBldr);
  1762. var getMethod = typeof(T).GetMethod("get_" + propertyName);
  1763. var setMethod = typeof(T).GetMethod("set_" + propertyName);
  1764. typeBuilder.DefineMethodOverride(currGetPropMthdBldr, getMethod);
  1765. typeBuilder.DefineMethodOverride(currSetPropMthdBldr, setMethod);
  1766. }
  1767. }
  1768. }
  1769. [AttributeUsage(AttributeTargets.Class)]
  1770. public class TableAttribute : Attribute
  1771. {
  1772. public TableAttribute(string tableName)
  1773. {
  1774. Name = tableName;
  1775. }
  1776. public string Name { get; private set; }
  1777. }
  1778. }