上傳Git的忽略文件下載 千萬不能忘記配置忽略文件,不然可能會搞得你一個項目10多個G,很煩人 先梳理下我們需要新建的項目如下。介面層一般I(i)開頭,實現層不需要。後面還會增加擴展類或者其他的。 API程式層:FastEasyAPI 服務介面層:FastEasy.IService 服務實現層:Fa ...
千萬不能忘記配置忽略文件,不然可能會搞得你一個項目10多個G,很煩人
先梳理下我們需要新建的項目如下。介面層一般I(i)開頭,實現層不需要。後面還會增加擴展類或者其他的。
API程式層:FastEasyAPI
服務介面層:FastEasy.IService
服務實現層:FastEasy.Service
倉儲介面層:FastEasy.IRepository
倉儲實現層:FastEasy.Repository
實體層:FastEasy.Model
倉儲模式的介紹很多大佬都有博客可以瞭解,我不會說什麼太專業的辭彙表達,我也記不得,我會按照我自己的理解來形容
首先,倉儲層(介面+實現),服務層(介面+實現),API程式層。這算是三層的結構,如果熟練或者精通了,不用建這麼多類庫,介面實現層可以合併或者使用泛型倉儲…讓項目短小精悍,不過目前我還理解不夠,所以搭建最基礎的倉儲模式。
接下來應該去添加訪問資料庫的對象
這個就有很多選擇了。Ado,ef,Sqlsugar等等。我剛出來工作的時候學的ado和ef,現在的話……唉,正如前文所說,一路cv過來的,現在都忘的差不多了。所以我選擇Sqlsugar!推薦!很棒!反正公司老項目就用他們封裝好的ef或者ado,如果有新項目需求,我都用sqlsugar,真的好用一批~特別是多租戶事務之類的,我很喜歡~(有點跑題了,繼續……)
原本我打算直接用來著,後來突然想起來,咱們都core了,怎麼可以不用依賴註入呢?所以嘞,這裡先穿插一下Autofac的使用,因為之前我單獨寫過autofac的教程,所以可能我會粘貼之前的文章內容,不懂的話可以留言或者百度,面向百度編程,是你最好的選擇!
Autofac的使用 Sqlsugar的註入使用
在api程式層引入autofac的包:Autofac.Extensions.DependencyInjection(內置依賴包含了autofac的基礎包)
這裡說下經驗之談,也不是我自己的經驗,就是隨著項目越來越大,Programs裡面的服務註冊會越來越多,所有我要在程式下麵新建一個文件夾Filter,裡面放我的各個模塊的註冊類,例如我要註入Sqlsugar,那我會在filter文件夾下新建一個類,起名:SqlsugarModule。然後關於Sqlsugar的註入配置都寫在此處,然後Programs里直接註入這個類就行,這樣後期不會因為註入很多東西導致Programs過於臃腫。
引入Sqlsugar 的包:SqlSugarCore。第一次接觸的話推薦大家去官網學習
Services.AddSingleton<ISqlSugarClient>(s => { SqlSugarScope db = new(new ConnectionConfig() { DbType = SqlSugar.DbType.Sqlite, ConnectionString = "DataSource=sqlsugar-dev.db", IsAutoCloseConnection = true, }); return db; });
scope單例註入,client非單例註入。官網的介紹是scope線程安全,排查問題方便,client非單例模式,性能比scope高5%左右。我是覺得性能差不多,scope可以讓我省心很多,嘿嘿嘿。
到這裡的話,sqlsugar其實已經註入完成了,就是這麼簡單,操作比ef方便很多啊,不過這種東西都是唯手熟爾,哪個你用著6就用哪個
創建基礎Base基類
寫到這兒發現前面的autofac說早了。抱歉各位。因為sqlsugar實在是很簡單,所以完全不需要用到autofac(笑死),不過都這樣了,就沒辦法了,反正下麵肯定會再說autofac的使用的。
上面註入了Sqlsuar的服務,代表著我們可以訪問資料庫了。
眾所周知,所有的功能需求到最後無非都是對資料庫的增刪改查,我們先不討論你業務邏輯怎麼搞,到最後你無非都是要搞一個實體,對資料庫新增,或者修改,或者搞一個id對著資料庫刪除數據。因此,無論你操作哪個表,都離不開這些增刪改查,所以這個Base基層,就是所有基礎的增刪改查,分頁查詢等。
簡單梳理下結構,首先我們有倉儲層,服務層,應用程式層。倉儲層和服務層都各有一個介面層和實現層。最基本的要新增4個類:IBaseRepository,BaseRepository。IBaseService,BaseRepository。因為對數據訪問在倉儲層,所以我們從Repository開始新建起:先介面後實現。(Base基層的倉儲層和服務層基本上一模一樣,其方法也只是滿足基本的增刪改查需求,若是複雜邏輯還需將基類定義為虛方法,在每張表獨立的倉儲層和服務層去重寫方法)
基礎方法囊括:單條增刪改查,批量增刪改查,分頁查詢
這是倉儲層的Base基類介面
/// <summary> /// 1條新增 /// </summary> /// <param name="entity">要創建的實體對象</param> /// <returns>如果成功創建實體記錄,則返回 true;否則返回 false。</returns> Task<bool> CreateEntityAsync(T entity); /// <summary> /// 批量新增 /// </summary> /// <param name="entities">要新增的實體對象集合</param> /// <returns>新增操作影響的記錄條數</returns> Task<int> CreateEntitysAsync(List<T> entitys); /// <summary> /// 1條修改 /// </summary> /// <param name="entity">要修改的實體對象</param> /// <returns>如果成功修改實體記錄,則返回 true;否則返回 false。</returns> Task<bool> UpdateEntityAsync(T entity); /// <summary> /// 批量修改 /// </summary> /// <param name="entities">要修改的實體對象集合</param> /// <returns>受影響的記錄數</returns> Task<int> UpdateEntitysAsync(List<T> entitys); /// <summary> /// 1條刪除 /// </summary> /// <param name="id">要刪除的記錄的主鍵ID。</param> /// <returns>刪除操作影響的記錄數。</returns> Task<bool> DeleteEntityByIdAsync(int id); /// <summary> /// 根據條件批量刪除 /// </summary> /// <param name="expression">條件</param> /// <returns>返回受影響條數</returns> Task<int> DeleteEntitysByWhereAsync(Expression<Func<T, bool>> expression); /// <summary> /// 查詢所有 /// </summary> /// <returns>返回實體集合</returns> Task<List<T>> GetEntitysAsync(); /// <summary> /// 根據ID單條查詢 /// </summary> /// <param name="id">主鍵ID</param> /// <returns>查詢到的實體</returns> Task<T> GetEntityByIdAsync(int id); /// <summary> /// 根據條件批量查詢。 /// </summary> /// <param name="expression">條件表達式</param> /// <returns>符合條件的實體集合</returns> Task<List<T>> GetEntitysByWhereAsync(Expression<Func<T, bool>> expression); /// <summary> /// 分頁查詢 /// </summary> /// <param name="pageNumber">頁碼,從1開始</param> /// <param name="pageSize">每頁條數</param> /// <param name="totalCount">總記錄數</param> /// <returns>查詢到的實體集合</returns> Task<List<T>> GetEntitysToPageAsync(int pageNumber, int pageSize, ref int totalCount);View Code
這是倉儲層Base基類實現。實現的是上面定義的Base基類介面
public class BaseRepository<T> : IBaseRepository<T> where T : class, new() { #region 構造 public BaseRepository(ISqlSugarClient _db) { db = _db; } #endregion 構造 protected readonly ISqlSugarClient db; public virtual async Task<bool> CreateEntityAsync(T entity) { try { return await db.Insertable<T>(entity).ExecuteCommandAsync() > 0; } catch (Exception) { return false; } } public virtual async Task<int> CreateEntitysAsync(List<T> entitys) { try { return await db.Insertable<T>(entitys).ExecuteCommandAsync(); } catch (Exception) { return 0; } } public virtual async Task<bool> DeleteEntityByIdAsync(int id) { try { return await db.Deleteable<T>().In(id).ExecuteCommandAsync() > 0; } catch (Exception) { return false; } } public virtual async Task<int> DeleteEntitysByWhereAsync(Expression<Func<T, bool>> expression) { try { return await db.Deleteable<T>().Where(expression).ExecuteCommandAsync(); } catch (Exception) { return 0; } } public virtual async Task<T> GetEntityByIdAsync(int id) { try { return await db.Queryable<T>().InSingleAsync(id); } catch (Exception) { return null; } } public virtual async Task<List<T>> GetEntitysAsync() { try { return await db.Queryable<T>().ToListAsync(); } catch (Exception) { return null; } } public virtual async Task<List<T>> GetEntitysByWhereAsync(Expression<Func<T, bool>> expression) { try { return await db.Queryable<T>().Where(expression).ToListAsync(); } catch (Exception) { return null; } } public virtual List<T> GetEntitysToPage(int pageNumber, int pageSize, ref int totalCount) { try { return db.Queryable<T>().ToPageList(pageNumber, pageSize, ref totalCount); } catch (Exception) { return null; } } public virtual async Task<bool> UpdateEntityAsync(T entity) { try { return await db.Updateable<T>(entity).ExecuteCommandAsync() > 0; } catch (Exception) { return false; } } public virtual async Task<int> UpdateEntitysAsync(List<T> entitys) { try { return await db.Updateable<T>(entitys).ExecuteCommandAsync(); } catch (Exception) { return 0; } } }View Code
基礎的增刪改差不多就這麼多了。寫的時候發現個小問題。就是根據id的增刪改查,其實也沒必要專門搞個方法,使用條件查詢方法就可以了,不過一開始沒考慮到,我覺得代碼復用性高一點說明寫的好,不過我這個並沒什麼太大影響。繼續~~
服務層的Base基類介面,這個完全可以複製倉儲層的base基類介面,不能說毫無關係,只能說完全一樣,所以這裡不寫咯。
服務層的Base基類實現,也差不多一樣,不同的是倉儲層是使用db訪問資料庫,而服務層是通過構造函數註入倉儲層的Base基類介面,通過調用介面方法來進行調用。
public class BaseService<T> : IBaseService<T> where T : class, new() { #region 構造 public BaseService(IBaseRepository<T> _baseRepository) { baseRepository = _baseRepository; } #endregion 構造 protected readonly IBaseRepository<T> baseRepository; public Task<bool> CreateEntityAsync(T entity) { return baseRepository.CreateEntityAsync(entity); } public Task<int> CreateEntitysAsync(List<T> entitys) { return baseRepository.CreateEntitysAsync(entitys); } public Task<bool> DeleteEntityByIdAsync(int id) { return baseRepository.DeleteEntityByIdAsync(id); } public Task<int> DeleteEntitysByWhereAsync(Expression<Func<T, bool>> expression) { return baseRepository.DeleteEntitysByWhereAsync(expression); } public Task<T> GetEntityByIdAsync(int id) { return baseRepository.GetEntityByIdAsync(id); } public Task<List<T>> GetEntitysAsync() { return baseRepository.GetEntitysAsync(); } public Task<List<T>> GetEntitysByWhereAsync(Expression<Func<T, bool>> expression) { return baseRepository.GetEntitysByWhereAsync(expression); } public List<T> GetEntitysToPage(int pageNumber, int pageSize, ref int totalCount) { return baseRepository.GetEntitysToPage(pageNumber, pageSize, ref totalCount); } public Task<bool> UpdateEntityAsync(T entity) { return baseRepository.UpdateEntityAsync(entity); } public Task<int> UpdateEntitysAsync(List<T> entitys) { return baseRepository.UpdateEntitysAsync(entitys); } }View Code
看到這裡的話,基本的倉儲模式已經搭建完成了,是的沒錯,就是這麼簡單。但是還沒有真正的去添加資料庫,所以只有基層,像這種普通的倉儲模式有個很麻煩的地方就是每一個表結構至少要在項目里添加4個類,所以還是比較麻煩的,所以最近在研究代碼生成,網上有很多現成的代碼生成器,不過我還是想自己研究研究,為了我這個開源項目的目標!我要搞個適配我這個項目的代碼生成器,畢竟自己寫的代碼我心裡有數~
都要一起加油喲~ 掰掰~
2023-9-20第一次更新內容:
有小伙伴建議我增加原生Sql的查詢,確實如此,所以在寫完代碼生成的文章後,我又在base基類添加了三個介面,分別是:
- 原生SQL查詢,返回List集合
- 原生SQL查詢,返回Datatable
- 存儲過程查詢,返回Datatable