.net6.0 webapi demo

BaseBusiness.cs 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. using System.Data;
  2. using System.Linq.Expressions;
  3. using System.Linq.Dynamic.Core;
  4. using EFCore.Sharding;
  5. using Microsoft.EntityFrameworkCore;
  6. using Net6Demo_Api.Util;
  7. using Microsoft.Extensions.Caching.Distributed;
  8. using System.Linq;
  9. using System.Reflection;
  10. using System.ComponentModel.DataAnnotations;
  11. using System.Data.Common;
  12. using MySqlConnector;
  13. using Net6Demo_Api.Entity;
  14. namespace Net6Demo_Api.Business
  15. {
  16. /// <summary>
  17. /// 描述:业务处理基类
  18. /// </summary>
  19. /// <typeparam name="T">泛型约束(数据库实体)</typeparam>
  20. public abstract class BaseBusiness<T> where T : class, new()
  21. {
  22. #region 构造函数
  23. /// <summary>
  24. /// 构造函数
  25. /// </summary>
  26. /// <param name="db">注入数据库</param>
  27. public BaseBusiness(IDbAccessor db, IDistributedCache cache, bool iscache = false)
  28. {
  29. _db = db;
  30. _cache = cache;
  31. if (iscache)
  32. {
  33. try { cache.Refresh(CacheName); IsCache = true; } catch { IsCache = false; }
  34. }
  35. }
  36. #endregion
  37. #region 私有成员
  38. /// <summary>
  39. /// 是否开启缓存(表中数据较少并且变化较少时建议使用,默认不开启)
  40. /// </summary>
  41. protected bool IsCache { get; set; } = false;
  42. /// <summary>
  43. /// 缓存名称
  44. /// </summary>
  45. protected string CacheName { get; set; } = typeof(T).Name;
  46. /// <summary>
  47. /// 主键字段
  48. /// </summary>
  49. protected PropertyInfo? KeyFiled
  50. {
  51. get
  52. {
  53. return typeof(T).GetProperties().Where(x => x.GetCustomAttribute<KeyAttribute>() != null).FirstOrDefault();
  54. }
  55. }
  56. #endregion
  57. #region 外部属性
  58. /// <summary>
  59. /// 业务仓储接口(支持软删除),支持联表操作
  60. /// 注:若需要访问逻辑删除的数据,请使用IDbAccessor.FullRepository
  61. /// 注:仅支持单线程操作
  62. /// </summary>
  63. public IDbAccessor _db { get; }
  64. /// <summary>
  65. /// 缓存接口
  66. /// </summary>
  67. public IDistributedCache _cache;
  68. #endregion
  69. #region 存在数据
  70. /// <summary>
  71. /// 存在数据
  72. /// </summary>
  73. /// <param name="condition">条件</param>
  74. /// <returns></returns>
  75. public bool Exists(Expression<Func<T, bool>> condition)
  76. {
  77. return _db.GetIQueryable<T>().Where(condition).Count() > 0;
  78. }
  79. /// <summary>
  80. /// 存在数据
  81. /// </summary>
  82. /// <param name="condition">条件</param>
  83. /// <returns></returns>
  84. public async Task<bool> ExistsAsync(Expression<Func<T, bool>> condition)
  85. {
  86. return await _db.GetIQueryable<T>().Where(condition).CountAsync() > 0;
  87. }
  88. #endregion
  89. #region 增加数据
  90. /// <summary>
  91. /// 添加数据
  92. /// </summary>
  93. /// <param name="entity">实体对象</param>
  94. public int Insert(T entity)
  95. {
  96. if (IsCache) OutRedis().Wait();
  97. return _db.Insert(entity);
  98. }
  99. /// <summary>
  100. /// 添加数据
  101. /// </summary>
  102. /// <param name="entity">实体对象</param>
  103. public async Task<int> InsertAsync(T entity)
  104. {
  105. if (IsCache) await OutRedis();
  106. return await _db.InsertAsync(entity);
  107. }
  108. /// <summary>
  109. /// 添加多条数据
  110. /// </summary>
  111. /// <param name="entities">实体对象集合</param>
  112. public int Insert(List<T> entities)
  113. {
  114. if (IsCache) OutRedis().Wait();
  115. return _db.Insert(entities);
  116. }
  117. /// <summary>
  118. /// 添加多条数据
  119. /// </summary>
  120. /// <param name="entities">实体对象集合</param>
  121. public async Task<int> InsertAsync(List<T> entities)
  122. {
  123. if (IsCache) await OutRedis();
  124. return await _db.InsertAsync(entities);
  125. }
  126. /// <summary>
  127. /// 批量添加数据,速度快
  128. /// </summary>
  129. /// <param name="entities"></param>
  130. public void BulkInsert(List<T> entities)
  131. {
  132. if (IsCache) OutRedis().Wait();
  133. _db.BulkInsert(entities);
  134. }
  135. #endregion
  136. #region 删除数据
  137. /// <summary>
  138. /// 删除指定主键数据
  139. /// </summary>
  140. /// <param name="key"></param>
  141. public int Delete(string key)
  142. {
  143. if (IsCache) OutRedis().Wait();
  144. return _db.Delete<T>(key);
  145. }
  146. /// <summary>
  147. /// 删除指定主键数据
  148. /// </summary>
  149. /// <param name="key"></param>
  150. public async Task<int> DeleteAsync(string key)
  151. {
  152. if (IsCache) await OutRedis();
  153. return await _db.DeleteAsync<T>(key);
  154. }
  155. /// <summary>
  156. /// 通过主键删除多条数据
  157. /// </summary>
  158. /// <param name="keys"></param>
  159. public int Delete(List<string> keys)
  160. {
  161. if (IsCache) OutRedis().Wait();
  162. return _db.Delete<T>(keys);
  163. }
  164. /// <summary>
  165. /// 通过主键删除多条数据
  166. /// </summary>
  167. /// <param name="keys"></param>
  168. public async Task<int> DeleteAsync(List<string> keys)
  169. {
  170. if (IsCache) await OutRedis();
  171. return await _db.DeleteAsync<T>(keys);
  172. }
  173. /// <summary>
  174. /// 删除指定条件数据
  175. /// </summary>
  176. /// <param name="condition">筛选条件</param>
  177. public int Delete(Expression<Func<T, bool>> condition)
  178. {
  179. if (IsCache) OutRedis().Wait();
  180. return _db.Delete(condition);
  181. }
  182. /// <summary>
  183. /// 删除指定条件数据
  184. /// </summary>
  185. /// <param name="condition">筛选条件</param>
  186. public async Task<int> DeleteAsync(Expression<Func<T, bool>> condition)
  187. {
  188. if (IsCache) await OutRedis();
  189. return await _db.DeleteAsync(condition);
  190. }
  191. #endregion
  192. #region 更新数据
  193. /// <summary>
  194. /// 更新一条数据
  195. /// </summary>
  196. /// <param name="entity">实体对象</param>
  197. /// <param name="properties">更新的实体属性</param>
  198. public int Update(T entity, List<string> properties = null)
  199. {
  200. if (IsCache) OutRedis().Wait();
  201. if (properties == null || properties.Count == 0)
  202. {
  203. return _db.Update(entity);
  204. }
  205. else
  206. {
  207. return _db.Update(entity, properties);
  208. }
  209. }
  210. /// <summary>
  211. /// 更新一条数据
  212. /// </summary>
  213. /// <param name="entity">实体对象</param>
  214. /// <param name="properties">更新的实体属性</param>
  215. public async Task<int> UpdateAsync(T entity, List<string> properties = null)
  216. {
  217. if (IsCache) await OutRedis();
  218. if (properties == null || properties.Count == 0)
  219. {
  220. return await _db.UpdateAsync(entity);
  221. }
  222. else
  223. {
  224. return await _db.UpdateAsync(entity, properties);
  225. }
  226. }
  227. /// <summary>
  228. /// 更新多条数据
  229. /// </summary>
  230. /// <param name="entities">数据列表</param>
  231. /// <param name="properties">更新的实体属性</param>
  232. public int Update(List<T> entities, List<string> properties = null)
  233. {
  234. if (IsCache) OutRedis().Wait();
  235. if (properties == null || properties.Count == 0)
  236. {
  237. return _db.Update(entities);
  238. }
  239. else
  240. {
  241. return _db.Update(entities, properties);
  242. }
  243. }
  244. /// <summary>
  245. /// 更新多条数据
  246. /// </summary>
  247. /// <param name="entities">数据列表</param>
  248. /// <param name="properties">更新的实体属性</param>
  249. public async Task<int> UpdateAsync(List<T> entities, List<string> properties = null)
  250. {
  251. if (IsCache) await OutRedis();
  252. if (properties == null || properties.Count == 0)
  253. {
  254. return await _db.UpdateAsync(entities);
  255. }
  256. else
  257. {
  258. return await _db.UpdateAsync(entities, properties);
  259. }
  260. }
  261. /// <summary>
  262. /// 指定条件更新
  263. /// </summary>
  264. /// <param name="whereExpre">筛选表达式</param>
  265. /// <param name="set">更改属性回调</param>
  266. public int Update(Expression<Func<T, bool>> whereExpre, Action<T> set)
  267. {
  268. if (IsCache) OutRedis().Wait();
  269. return _db.Update(whereExpre, set);
  270. }
  271. /// <summary>
  272. /// 指定条件更新
  273. /// </summary>
  274. /// <param name="whereExpre">筛选表达式</param>
  275. /// <param name="set">更改属性回调</param>
  276. public async Task<int> UpdateAsync(Expression<Func<T, bool>> whereExpre, Action<T> set)
  277. {
  278. if (IsCache) await OutRedis();
  279. return await _db.UpdateAsync(whereExpre, set);
  280. }
  281. /// <summary>
  282. /// 使用SQL语句按照条件更新(指定字段)
  283. /// </summary>
  284. /// <param name="where">筛选条件</param>
  285. /// <param name="fieldvalues">字段值设置</param>
  286. /// <returns>影响条数</returns>
  287. public int UpdateSql(Expression<Func<T, bool>> where, Dictionary<string, object?> fieldvalues)
  288. {
  289. if (IsCache) OutRedis().Wait();
  290. List<(string, UpdateType, object)> values = new List<(string, UpdateType, object)>();
  291. foreach (var item in fieldvalues)
  292. {
  293. values.Add((item.Key, UpdateType.Equal, item.Value));
  294. }
  295. return _db.UpdateSql(where, values.ToArray());
  296. }
  297. /// <summary>
  298. /// 使用SQL语句按照条件更新(指定字段)
  299. /// </summary>
  300. /// <param name="where">筛选条件</param>
  301. /// <param name="fieldvalues">字段值设置</param>
  302. /// <returns>影响条数</returns>
  303. public async Task<int> UpdateSqlAsync(Expression<Func<T, bool>> where, Dictionary<string,object?> fieldvalues)
  304. {
  305. if (IsCache) await OutRedis();
  306. List<(string, UpdateType, object)> values = new List<(string, UpdateType, object)>();
  307. foreach (var item in fieldvalues)
  308. {
  309. values.Add((item.Key, UpdateType.Equal, item.Value));
  310. }
  311. return await _db.UpdateSqlAsync(where, values.ToArray());
  312. }
  313. #endregion
  314. #region 查询数据
  315. /// <summary>
  316. /// 获取实体
  317. /// </summary>
  318. /// <param name="keyValue">主键</param>
  319. /// <returns></returns>
  320. public T GetEntity(params object[] keyValue)
  321. {
  322. #region 启用缓存
  323. if (IsCache)
  324. {
  325. return GetIQueryable().Where(p => KeyFiled.GetValue(p).ToString() == keyValue[0].ToString()).FirstOrDefault();
  326. }
  327. #endregion
  328. return _db.GetEntity<T>(keyValue);
  329. }
  330. /// <summary>
  331. /// 获取实体
  332. /// </summary>
  333. /// <param name="keyValue">主键</param>
  334. /// <returns></returns>
  335. public async Task<T> GetEntityAsync(params object[] keyValue)
  336. {
  337. #region 启用缓存
  338. if (IsCache)
  339. {
  340. return GetIQueryable().Where(p => KeyFiled.GetValue(p).ToString() == keyValue[0].ToString()).FirstOrDefault();
  341. }
  342. #endregion
  343. return await _db.GetEntityAsync<T>(keyValue);
  344. }
  345. /// <summary>
  346. /// 根据条件获取数量
  347. /// </summary>
  348. /// <returns></returns>
  349. public int GetCount(Expression<Func<T, bool>> condition)
  350. {
  351. return GetIQueryable().Where(condition).Count();
  352. }
  353. /// <summary>
  354. /// 根据条件获取数量
  355. /// </summary>
  356. /// <returns></returns>
  357. public async Task<int> GetCountAsync(Expression<Func<T, bool>> condition)
  358. {
  359. var query = GetIQueryable().Where(condition);
  360. if (IsCache) return query.Count();
  361. return await query.CountAsync();
  362. }
  363. /// <summary>
  364. /// 获取表的所有数据,当数据量很大时不要使用!
  365. /// </summary>
  366. /// <returns></returns>
  367. public List<T> GetList()
  368. {
  369. return GetIQueryable().ToList();
  370. }
  371. /// <summary>
  372. /// 根据条件获取列表,当数据量很大时不要使用!
  373. /// </summary>
  374. /// <param name="condition">条件</param>
  375. /// <returns></returns>
  376. public List<T> GetList(Expression<Func<T, bool>> condition)
  377. {
  378. var query = GetIQueryable().Where(condition);
  379. return query.ToList();
  380. }
  381. /// <summary>
  382. /// 获取表的所有数据,当数据量很大时不要使用!
  383. /// </summary>
  384. /// <returns></returns>
  385. public async Task<List<T>> GetListAsync()
  386. {
  387. var query = GetIQueryable();
  388. if (IsCache) return query.ToList();
  389. return await query.ToListAsync();
  390. }
  391. /// <summary>
  392. /// 根据条件获取列表,当数据量很大时不要使用!
  393. /// </summary>
  394. /// <param name="condition">条件</param>
  395. /// <returns></returns>
  396. public async Task<List<T>> GetListAsync(Expression<Func<T, bool>> condition)
  397. {
  398. var query = GetIQueryable().Where(condition);
  399. if (IsCache) return query.ToList();
  400. return await query.ToListAsync();
  401. }
  402. /// <summary>
  403. /// 分页获取数据
  404. /// </summary>
  405. /// <param name="page">分页信息</param>
  406. /// <param name="condition">条件</param>
  407. /// <param name="orderBy">排序</param>
  408. /// <returns></returns>
  409. public async Task<ValueTuple<List<T>, int>> GetListPageAsync(PageInput page, Expression<Func<T, bool>> condition, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy)
  410. {
  411. var iq = GetIQueryable().Where(condition);
  412. var query = orderBy(iq).Skip((page.PageIndex - 1) * page.PageRows).Take(page.PageRows);
  413. if (IsCache)
  414. {
  415. return (query.ToList(), iq.Count());
  416. }
  417. var list = await query.ToListAsync();
  418. int total = await iq.CountAsync();
  419. return (list, total);
  420. }
  421. /// <summary>
  422. /// 获取实体对应的表,延迟加载,主要用于支持Linq查询操作
  423. /// </summary>
  424. /// <returns></returns>
  425. public virtual IQueryable<T> GetIQueryable()
  426. {
  427. if (IsCache)
  428. {
  429. var listCache = GetRedis().Result;
  430. if (listCache != null)
  431. {
  432. return listCache.AsQueryable();
  433. }
  434. }
  435. return _db.GetIQueryable<T>().AsNoTracking();
  436. }
  437. #endregion
  438. #region 执行Sql语句
  439. /// <summary>
  440. /// 执行sql
  441. /// </summary>
  442. /// <returns></returns>
  443. public int ExecuteSql(string sql, params (string, object)[] paras)
  444. {
  445. if (IsCache) OutRedis().Wait();
  446. return _db.ExecuteSql(sql, paras);
  447. }
  448. /// <summary>
  449. /// 执行sql异步
  450. /// </summary>
  451. /// <returns></returns>
  452. public async Task<int> ExecuteSqlAsync(string sql, params (string, object)[] paras)
  453. {
  454. if (IsCache) await OutRedis();
  455. return await _db.ExecuteSqlAsync(sql, paras);
  456. }
  457. /// <summary>
  458. /// 通过Sql语句查询返回DataSet,参数化查询
  459. /// </summary>
  460. /// <param name="sql">Sql语句</param>
  461. /// <param name="parameters">参数</param>
  462. /// <returns></returns>
  463. public DataSet GetDataSetWithSql(string sql, List<DbParameter> parameters = null)
  464. {
  465. DbProviderFactory dbProviderFactory = MySqlConnectorFactory.Instance;
  466. using (DbConnection conn = dbProviderFactory.CreateConnection())
  467. {
  468. conn.ConnectionString = _db.ConnectionString;
  469. if (conn.State != ConnectionState.Open)
  470. {
  471. conn.Open();
  472. }
  473. using (DbCommand cmd = conn.CreateCommand())
  474. {
  475. cmd.Connection = conn;
  476. cmd.CommandText = sql;
  477. if (parameters != null && parameters.Count > 0)
  478. {
  479. foreach (var item in parameters)
  480. {
  481. cmd.Parameters.Add(item);
  482. }
  483. }
  484. DbDataAdapter adapter = dbProviderFactory.CreateDataAdapter();
  485. adapter.SelectCommand = cmd;
  486. DataSet ds = new DataSet();
  487. adapter.Fill(ds);
  488. cmd.Parameters.Clear();
  489. return ds;
  490. }
  491. }
  492. }
  493. #endregion
  494. #region 缓存数据
  495. /// <summary>
  496. /// 获取缓存
  497. /// </summary>
  498. /// <returns></returns>
  499. private async Task<List<T>?> GetRedis()
  500. {
  501. var strList = await _cache.GetStringAsync(CacheName);
  502. if (strList != null)
  503. {
  504. return strList.ToObject<List<T>>();
  505. }
  506. else
  507. {
  508. return await InRedis();
  509. }
  510. }
  511. /// <summary>
  512. /// 插入缓存
  513. /// </summary>
  514. /// <returns></returns>
  515. private async Task<List<T>> InRedis()
  516. {
  517. var list = await _db.GetIQueryable<T>().AsNoTracking().ToListAsync();
  518. await _cache.SetStringAsync(CacheName, list.ToJson(), new DistributedCacheEntryOptions()
  519. {
  520. AbsoluteExpirationRelativeToNow = new TimeSpan(24, 0, 0)
  521. });
  522. return list;
  523. }
  524. /// <summary>
  525. /// 移除缓存
  526. /// </summary>
  527. private async Task OutRedis()
  528. {
  529. await _cache.RemoveAsync(CacheName);
  530. }
  531. #endregion
  532. }
  533. }