DbDataReaderExtensions.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. using EasyDevCore.Database;
  2. using EasyDevCore.Database.EntityTable;
  3. using EasyDevCore.Common;
  4. using System.Data;
  5. using System.Data.Common;
  6. using System.Dynamic;
  7. using System.Text;
  8. namespace EasyDevCore.Database
  9. {
  10. /// <summary>
  11. ///
  12. /// </summary>
  13. public static class DbDataReaderExtensions
  14. {
  15. /// <summary>
  16. /// Gets the value.
  17. /// </summary>
  18. /// <typeparam name="T"></typeparam>
  19. /// <param name="reader">The reader.</param>
  20. /// <param name="fieldName">Name of the field.</param>
  21. /// <param name="valueIfNull">The value if null.</param>
  22. /// <returns></returns>
  23. public static T GetValue<T>(this DbDataReader reader, string fieldName, T valueIfNull)
  24. {
  25. int colIndex = reader.GetOrdinal(fieldName);
  26. object value = reader.GetValue(colIndex);
  27. if (value == null) return valueIfNull;
  28. Type columnType = reader.GetFieldType(colIndex);
  29. if (typeof(T) == columnType)
  30. {
  31. return (T)value;
  32. }
  33. else
  34. {
  35. return (T)Convert.ChangeType(value, columnType);
  36. }
  37. }
  38. /// <summary>
  39. /// Gets the row.
  40. /// </summary>
  41. /// <param name="reader">The reader.</param>
  42. /// <returns></returns>
  43. public static dynamic GetRow(this DbDataReader reader)
  44. {
  45. IDictionary<string, object> expandoObject = new ExpandoObject() as IDictionary<string, object>;
  46. var fieldCount = reader.FieldCount;
  47. for (var i = 0; i < fieldCount; i++)
  48. expandoObject.Add(reader.GetName(i), reader.IsDBNull(i) ? null : reader[i]);
  49. return expandoObject;
  50. }
  51. /// <summary>
  52. /// Gets the row asynchronous.
  53. /// </summary>
  54. /// <param name="reader">The reader.</param>
  55. /// <param name="cancellationToken">The cancellation token.</param>
  56. /// <returns></returns>
  57. public static async Task<dynamic> GetRowAsync(this DbDataReader reader, CancellationToken cancellationToken)
  58. {
  59. var expandoObject = new ExpandoObject() as IDictionary<string, object>;
  60. for (var i = 0; i < reader.FieldCount; i++)
  61. {
  62. object value = await reader.IsDBNullAsync(i, cancellationToken).ConfigureAwait(false) ? null : reader.GetValue(i);
  63. expandoObject.Add(reader.GetName(i), value);
  64. }
  65. return expandoObject;
  66. }
  67. /// <summary>
  68. /// Fetches to json.
  69. /// </summary>
  70. /// <param name="reader">The reader.</param>
  71. /// <param name="indentFormat">if set to <c>true</c> [indent format].</param>
  72. /// <returns></returns>
  73. public static string FetchToJson(this DbDataReader reader, bool indentFormat = false)
  74. {
  75. if (reader.IsClosed) return null;
  76. var JSONString = new StringBuilder();
  77. if (indentFormat)
  78. {
  79. JSONString.AppendLine("[");
  80. while (reader.Read())
  81. {
  82. JSONString.AppendLine("{");
  83. for (int i = 0; i < reader.FieldCount; i++)
  84. {
  85. string value = "\"" + reader.GetName(i) + "\":"
  86. + (reader.IsDBNull(i) ? "null" :
  87. "\"" + System.Web.HttpUtility.JavaScriptStringEncode(reader[i].StringFrom()) + "\""
  88. );
  89. if (i < reader.FieldCount - 1)
  90. {
  91. value += ",";
  92. }
  93. JSONString.AppendLine(value);
  94. }
  95. JSONString.AppendLine("}");
  96. }
  97. JSONString.AppendLine("]");
  98. }
  99. else
  100. {
  101. JSONString.Append("[");
  102. while (reader.Read())
  103. {
  104. JSONString.Append("{");
  105. for (int i = 0; i < reader.FieldCount; i++)
  106. {
  107. string value = "\"" + reader.GetName(i) + "\":"
  108. + (reader.IsDBNull(i) ? "null" :
  109. "\"" + System.Web.HttpUtility.JavaScriptStringEncode(reader[i].StringFrom()) + "\""
  110. );
  111. if (i < reader.FieldCount - 1)
  112. {
  113. value += ",";
  114. }
  115. JSONString.Append(value);
  116. }
  117. JSONString.Append("}");
  118. }
  119. JSONString.Append("]");
  120. }
  121. return JSONString.ToString();
  122. }
  123. /// <summary>
  124. /// Fetches to json asynchronous.
  125. /// </summary>
  126. /// <param name="reader">The reader.</param>
  127. /// <param name="indentFormat">if set to <c>true</c> [indent format].</param>
  128. /// <param name="cancellationToken">The cancellation token.</param>
  129. /// <returns></returns>
  130. public static async Task<string> FetchToJsonAsync(this DbDataReader reader, bool indentFormat = false, CancellationToken cancellationToken = default)
  131. {
  132. if (reader.IsClosed) return null;
  133. var JSONString = new StringBuilder();
  134. if (indentFormat)
  135. {
  136. JSONString.AppendLine("[");
  137. while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
  138. {
  139. JSONString.AppendLine("{");
  140. for (int i = 0; i < reader.FieldCount; i++)
  141. {
  142. string value = "\"" + reader.GetName(i) + "\":"
  143. + (await reader.IsDBNullAsync(i, cancellationToken).ConfigureAwait(false) ? "null" : "\"" +
  144. System.Web.HttpUtility.JavaScriptStringEncode(reader[i].StringFrom()) + "\"");
  145. if (i < reader.FieldCount - 1)
  146. {
  147. value += ",";
  148. }
  149. JSONString.AppendLine(value);
  150. }
  151. JSONString.AppendLine("}");
  152. }
  153. JSONString.AppendLine("]");
  154. }
  155. else
  156. {
  157. JSONString.Append("[");
  158. while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
  159. {
  160. JSONString.Append("{");
  161. for (int i = 0; i < reader.FieldCount; i++)
  162. {
  163. string value = "\"" + reader.GetName(i) + "\":"
  164. + (await reader.IsDBNullAsync(i, cancellationToken).ConfigureAwait(false) ? "null" : "\"" +
  165. System.Web.HttpUtility.JavaScriptStringEncode(reader[i].StringFrom()) + "\"");
  166. if (i < reader.FieldCount - 1)
  167. {
  168. value += ",";
  169. }
  170. JSONString.Append(value);
  171. }
  172. JSONString.Append("}");
  173. }
  174. JSONString.Append("]");
  175. }
  176. return JSONString.ToString();
  177. }
  178. /// <summary>
  179. /// Fetches to list.
  180. /// </summary>
  181. /// <param name="reader">The reader.</param>
  182. /// <returns></returns>
  183. public static IList<dynamic> FetchToDynamic(this DbDataReader reader)
  184. {
  185. if (reader.IsClosed) return null;
  186. List<dynamic> list = new();
  187. while (reader.Read())
  188. {
  189. list.Add(reader.GetRow());
  190. }
  191. return list;
  192. }
  193. /// <summary>
  194. /// Fetches to dynamic asynchronous.
  195. /// </summary>
  196. /// <param name="reader">The reader.</param>
  197. /// <param name="cancellationToken">The cancellation token.</param>
  198. /// <returns></returns>
  199. public static async Task<IList<dynamic>> FetchToDynamicAsync(this DbDataReader reader, CancellationToken cancellationToken = default)
  200. {
  201. if (reader.IsClosed) return null;
  202. List<dynamic> list = new();
  203. DataRecordDynamic wrapper = new(reader);
  204. while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
  205. {
  206. list.Add(await reader.GetRowAsync(cancellationToken).ConfigureAwait(false));
  207. }
  208. bool hasNextResult = await reader.NextResultAsync(cancellationToken).ConfigureAwait(false);
  209. if (!hasNextResult) await reader.CloseAsync().ConfigureAwait(false);
  210. return list;
  211. }
  212. /// <summary>
  213. /// Fetches the fill list internal.
  214. /// </summary>
  215. /// <typeparam name="T"></typeparam>
  216. /// <param name="reader">The reader.</param>
  217. /// <param name="list">The list.</param>
  218. /// <returns></returns>
  219. private static IList<T> FetchFillListInternal<T>(this DbDataReader reader, IList<T> list)
  220. where T : class, new()
  221. {
  222. if (reader.IsClosed) return null;
  223. var mapper = new DbDataReaderMapper<T>(reader);
  224. mapper.Map(row => list.Add(row));
  225. bool hasNextResult = reader.NextResult();
  226. if (!hasNextResult) reader.Close();
  227. return list;
  228. }
  229. /// <summary>
  230. /// Fetches the fill list internal asynchronous.
  231. /// </summary>
  232. /// <typeparam name="T"></typeparam>
  233. /// <param name="reader">The reader.</param>
  234. /// <param name="list">The list.</param>
  235. /// <param name="cancellationToken">The cancellation token.</param>
  236. /// <returns></returns>
  237. private async static Task<IList<T>> FetchFillListInternalAsync<T>(this DbDataReader reader, IList<T> list, CancellationToken cancellationToken = default)
  238. where T : class, new()
  239. {
  240. if (reader.IsClosed) return null;
  241. var mapper = new DbDataReaderMapper<T>(reader);
  242. await mapper.MapAsync(row => list.Add(row), cancellationToken).ConfigureAwait(false);
  243. bool hasNextResult = await reader.NextResultAsync(cancellationToken).ConfigureAwait(false);
  244. if (!hasNextResult) await reader.CloseAsync().ConfigureAwait(false);
  245. return list;
  246. }
  247. /// <summary>
  248. /// Fetches the fill list.
  249. /// </summary>
  250. /// <typeparam name="T"></typeparam>
  251. /// <param name="reader">The reader.</param>
  252. /// <param name="list">The list.</param>
  253. /// <returns></returns>
  254. public static int FetchFillList<T>(this DbDataReader reader, IList<T> list)
  255. where T : class, new()
  256. {
  257. int rowsCount = list.Count;
  258. return reader.FetchFillListInternal(list).Count - rowsCount;
  259. }
  260. /// <summary>
  261. /// Fetches the fill list asynchronous.
  262. /// </summary>
  263. /// <typeparam name="T"></typeparam>
  264. /// <param name="reader">The reader.</param>
  265. /// <param name="list">The list.</param>
  266. /// <param name="cancellationToken">The cancellation token.</param>
  267. /// <returns></returns>
  268. public static async Task<int> FetchFillListAsync<T>(this DbDataReader reader, IList<T> list, CancellationToken cancellationToken = default)
  269. where T : class, new()
  270. {
  271. int rowsCount = list.Count;
  272. return (await reader.FetchFillListInternalAsync(list, cancellationToken).ConfigureAwait(false)).Count - rowsCount;
  273. }
  274. /// <summary>
  275. /// Fetches to list.
  276. /// </summary>
  277. /// <typeparam name="TResult">The type of the result.</typeparam>
  278. /// <param name="reader">The reader.</param>
  279. /// <param name="selector">The selector.</param>
  280. /// <returns></returns>
  281. public static IList<TResult> FetchToList<TResult>(this DbDataReader reader, Func<dynamic, TResult> selector)
  282. {
  283. if (reader.IsClosed) return null;
  284. List<TResult> list = new();
  285. DataRecordDynamic wrapper = new(reader);
  286. while (reader.Read())
  287. {
  288. var item = selector(wrapper);
  289. list.Add(item);
  290. }
  291. bool hasNextResult = reader.NextResult();
  292. if (!hasNextResult) reader.Close();
  293. return list;
  294. }
  295. /// <summary>
  296. /// Fetches to list asynchronous.
  297. /// </summary>
  298. /// <typeparam name="TResult">The type of the result.</typeparam>
  299. /// <param name="reader">The reader.</param>
  300. /// <param name="selector">The selector.</param>
  301. /// <param name="cancellationToken">The cancellation token.</param>
  302. /// <returns></returns>
  303. public static async Task<IList<TResult>> FetchToListAsync<TResult>(this DbDataReader reader, Func<dynamic, TResult> selector, CancellationToken cancellationToken = default)
  304. {
  305. if (reader.IsClosed) return null;
  306. List<TResult> list = new();
  307. DataRecordDynamic wrapper = new(reader);
  308. while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
  309. {
  310. var item = selector(wrapper);
  311. list.Add(item);
  312. }
  313. bool hasNextResult = await reader.NextResultAsync(cancellationToken).ConfigureAwait(false);
  314. if (!hasNextResult) await reader.CloseAsync().ConfigureAwait(false);
  315. return list;
  316. }
  317. /// <summary>
  318. /// Fetches to list.
  319. /// </summary>
  320. /// <typeparam name="T"></typeparam>
  321. /// <param name="reader">The reader.</param>
  322. /// <param name="list">The list.</param>
  323. /// <returns></returns>
  324. public static IList<T> FetchToList<T>(this DbDataReader reader, IList<T> list = null)
  325. where T : class, new()
  326. {
  327. if (reader.IsClosed) return list;
  328. IList<T> listNew = list ?? new List<T>();
  329. listNew.Clear();
  330. return reader.FetchFillListInternal(listNew);
  331. }
  332. /// <summary>
  333. /// Fetches to list asynchronous.
  334. /// </summary>
  335. /// <typeparam name="T"></typeparam>
  336. /// <param name="reader">The reader.</param>
  337. /// <param name="list">The list.</param>
  338. /// <param name="cancellationToken">The cancellation token.</param>
  339. /// <returns></returns>
  340. public static async Task<IList<T>> FetchToListAsync<T>(this DbDataReader reader, IList<T> list = null, CancellationToken cancellationToken = default)
  341. where T : class, new()
  342. {
  343. if (reader.IsClosed) return list;
  344. IList<T> listNew = list ?? new List<T>();
  345. listNew.Clear();
  346. return await reader.FetchFillListInternalAsync(listNew, cancellationToken).ConfigureAwait(false);
  347. }
  348. /// <summary>
  349. /// Fetches the fill data set.
  350. /// </summary>
  351. /// <param name="reader">The reader.</param>
  352. /// <param name="dataSet">The data set.</param>
  353. public static int FetchFillDataSet(this DbDataReader reader, DataSet dataSet)
  354. {
  355. if (dataSet.Tables.Count == 0) return 0;
  356. var totalRows = dataSet.Tables.Cast<DataTable>().Sum(tb => tb.Rows.Count);
  357. int i = 0;
  358. do
  359. {
  360. dataSet.Tables[i].Load(reader);
  361. i++;
  362. } while (dataSet.Tables.Count > i && !reader.IsClosed);
  363. return dataSet.Tables.Cast<DataTable>().Sum(tb => tb.Rows.Count) - totalRows;
  364. }
  365. /// <summary>
  366. /// Fetches the fill data set asynchronous.
  367. /// </summary>
  368. /// <param name="reader">The reader.</param>
  369. /// <param name="dataSet">The data set.</param>
  370. /// <param name="cancellationToken">The cancellation token.</param>
  371. /// <returns></returns>
  372. public static async Task<int> FetchFillDataSetAsync(this DbDataReader reader, DataSet dataSet, CancellationToken cancellationToken = default)
  373. {
  374. if (dataSet.Tables.Count == 0) return 0;
  375. var totalRows = dataSet.Tables.Cast<DataTable>().Sum(tb => tb.Rows.Count);
  376. int i = 0;
  377. do
  378. {
  379. await dataSet.Tables[i].LoadAsync(reader, cancellationToken).ConfigureAwait(false);
  380. } while (dataSet.Tables.Count > i && !reader.IsClosed);
  381. return dataSet.Tables.Cast<DataTable>().Sum(tb => tb.Rows.Count) - totalRows;
  382. }
  383. // <summary>
  384. /// <summary>
  385. /// Fetches to data set.
  386. /// </summary>
  387. /// <param name="reader">The reader.</param>
  388. /// <param name="dataSet">The data set.</param>
  389. /// <param name="parameters">The parameters.</param>
  390. /// <returns></returns>
  391. public static DataSet FetchToDataSet(this DbDataReader reader, DataSet dataSet = null, EasyDbParameterCollection parameters = null)
  392. {
  393. if (dataSet != null) dataSet.Clear();
  394. DataSet newDataSet = dataSet ?? new DataSet();
  395. do
  396. {
  397. newDataSet.Tables.Add().Load(reader, LoadOption.Upsert);
  398. if (parameters != null)
  399. {
  400. var result = ParameterUtils.GatherOutputParameters(0, parameters);
  401. foreach (var item in result)
  402. {
  403. newDataSet.ExtendedProperties[item.Key] = item.Value;
  404. }
  405. }
  406. } while (!reader.IsClosed);
  407. return newDataSet;
  408. }
  409. /// <summary>
  410. /// Fetches to data set asynchronous.
  411. /// </summary>
  412. /// <param name="reader">The reader.</param>
  413. /// <param name="DataSet">The entity set.</param>
  414. /// <param name="cancellationToken">The cancellation token.</param>
  415. /// <returns></returns>
  416. public static async Task<DataSet> FetchToDataSetAsync(this DbDataReader reader, DataSet DataSet = null, CancellationToken cancellationToken = default)
  417. {
  418. if (DataSet != null) DataSet.Clear();
  419. DataSet newDataSet = DataSet ?? new DataSet();
  420. do
  421. {
  422. await newDataSet.Tables.Add().LoadAsync(reader, cancellationToken).ConfigureAwait(false);
  423. } while (!reader.IsClosed);
  424. return newDataSet;
  425. }
  426. /// <summary>
  427. /// Fetches to table.
  428. /// </summary>
  429. /// <param name="reader">The reader.</param>
  430. /// <param name="table">The table.</param>
  431. /// <returns></returns>
  432. public static int FetchFillTable(this DbDataReader reader, DataTable table)
  433. {
  434. int totalRows = table.Rows.Count;
  435. table.Load(reader);
  436. return table.Rows.Count - totalRows;
  437. }
  438. /// <summary>
  439. /// Fetches to table.
  440. /// </summary>
  441. /// <param name="reader">The reader.</param>
  442. /// <param name="table">The table.</param>
  443. /// <param name="cancellationToken">The cancellation token.</param>
  444. /// <returns></returns>
  445. public static async Task<int> FetchFillTableAsync(this DbDataReader reader, DataTable table, CancellationToken cancellationToken = default)
  446. {
  447. if (reader.IsClosed) return 0;
  448. int totalRows = table.Rows.Count;
  449. await table.LoadAsync(reader);
  450. return table.Rows.Count - totalRows;
  451. }
  452. /// <summary>
  453. /// Fetches to table.
  454. /// </summary>
  455. /// <param name="reader">The reader.</param>
  456. /// <param name="table">The table.</param>
  457. /// <returns></returns>
  458. public static DataTable FetchToTable(this DbDataReader reader, DataTable table = null)
  459. {
  460. if (table != null) table.Clear();
  461. DataTable newTable = table ?? new DataTable();
  462. newTable.Load(reader);
  463. return newTable;
  464. }
  465. /// <summary>
  466. /// Fetches to table asynchronous.
  467. /// </summary>
  468. /// <param name="reader">The reader.</param>
  469. /// <param name="table">The table.</param>
  470. /// <param name="cancellationToken">The cancellation token.</param>
  471. /// <returns></returns>
  472. public static async Task<DataTable> FetchToTableAsync(this DbDataReader reader, DataTable table = null, CancellationToken cancellationToken = default)
  473. {
  474. if (table != null) table.Clear();
  475. DataTable newTable = table ?? new DataTable();
  476. await newTable.LoadAsync(reader, cancellationToken).ConfigureAwait(false);
  477. return newTable;
  478. }
  479. }
  480. }