.net6.0 webapi demo

BaseBusiness.cs 17KB

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