1. 程式人生 > >從壹開始前後端分離【 .NET Core2.0 +Vue2.0 】框架之八 || API專案整體搭建 6.3 非同步泛型倉儲+依賴注入初探

從壹開始前後端分離【 .NET Core2.0 +Vue2.0 】框架之八 || API專案整體搭建 6.3 非同步泛型倉儲+依賴注入初探

程式碼已上傳Github+Gitee,文末有地址

  番外:在上文中,也是遇到了大家見仁見智的評論和反對,嗯~說實話,積極性稍微受到了一丟丟的打擊,不過還好,還是有很多很多很多人的贊同的,所以會一直堅持下去,歡迎提出各種建議,問題,意見等,我這個系列呢,只是一個拋磚引玉的文章,大家可以自定義的去擴充套件學習,比如你看了.net core api,可以自學.net core mvc呀;看了sqlsugar,可以自學EF,Deppar呀;看了vue,可以自學React、Angular呀,我也是個小白,大家進步是本系列文章的唯一目標。

Sqlsugar和EF一樣,表示式樹,不用寫sql,但是支援sql,支援多種型別資料庫(MSSQL,Oracle,Mysql,SQLite),配置簡單;

僅僅是一個數據訪問層,100k輕量級,方便遷移;

  關於速率呢,我簡單的做了一個測試,使用公司的資料表,一共4千萬條資料,我遍歷全表,並提取前一萬條(當然資料庫有主鍵索引,一般分頁100條也夠多了吧),一共1.6s,截圖如下:

網友互動

昨天也收到了很多人的問題和反饋,關於DbConfig連線字串,@(這裡把您的暱稱放出來,不會侵權吧,可以私信我,我刪掉),有新的方法,我很感謝他,把他的方法寫出來

 可參考網文地址:配置和選項

1、在appsettings.json 中新增
"AppSettings": {
"SqlServerConnection": "Server=.;Database=BlogDB;User ID=sa;Password=sa;
", "ProviderName": "System.Data.SqlClient" }, 2、在ConfigureServices(IServiceCollection services) 方法中新增 //資料庫配置 BaseDBConfig.ConnectionString = Configuration.GetSection("AppSettings:SqlServerConnection").Value; 3、修改BaseDBConfig.cs public static string ConnectionString { get; set; }

我在之後的專案中會使用他的這個方法,並且做一個擴充套件,這裡先寫上,如果大家都有好的意見或建議,我都會在下一篇文章中寫出來,大家一起學習。

 好啦,昨天已經總結好了,開始今天的講解。

緣起

在上一節中,我們實現了倉儲層的構造,並聯通了資料庫,調取了資料,整理搭建已經有了一個雛形,今天就繼續往下探討,寫一個非同步泛型倉儲

使用非同步Async/Aswait呢,還是很方便的,不過,如果要使用非同步,就要非同步到底,不然就會阻塞,變成了同步,還是鼓勵大家練習下,就算是出現錯誤了,那就證明學習到了,哈哈哈[哭笑];

泛型呢,用到的是介面和基類,可以極大的減少工作量;

零、今天完成的淺紫色部分

 

一、在Blog.Core.IRepository 層中新增BASE資料夾,並新增介面 IBaseRepository.cs

  我自己從SimpleClient中,抽取了基本的常見方法做封裝,你也可以自己自定義封裝擴充套件,有人問我,既然Sqlsugar都已經封裝好了SimpleClient,為什麼我還要在倉儲中再一次封裝,我是這麼想的,如果一個專案中來了一個新人,之前用過EF或者Sqlhelper,那他來了,需要在重新學習一遍Sqlsugar了,這個時間上,至少一兩天吧,所以封裝基本的介面後,他只需要按照之前的開發方法使用就行,不需要了解底層,當然這個還是個小栗子,其實大公司都是這樣的,更新迭代很快,沒有精力從新學習,所以這也就是面向介面程式設計的好處,我曾經在微軟的專案中就充分的感受到這個境況。

注意:我這裡沒有封裝多表查詢,其實是可以寫的,參考地址 多表查詢, 如果各位會封裝的話,可以留言,感激不盡

    public interface IBaseRepository<TEntity> where TEntity : class
    {

        Task<TEntity> QueryByID(object objId);
        Task<TEntity> QueryByID(object objId, bool blnUseCache = false);
        Task<List<TEntity>> QueryByIDs(object[] lstIds);

        Task<int> Add(TEntity model);

        Task<bool> DeleteById(object id);

        Task<bool> Delete(TEntity model);

        Task<bool> DeleteByIds(object[] ids);

        Task<bool> Update(TEntity model);
        Task<bool> Update(TEntity entity, string strWhere);
        Task<bool> Update(TEntity entity, List<string> lstColumns = null, List<string> lstIgnoreColumns = null, string strWhere = "");

        Task<List<TEntity>> Query();
        Task<List<TEntity>> Query(string strWhere);
        Task<List<TEntity>> Query(Expression<Func<TEntity, bool>> whereExpression);
        Task<List<TEntity>> Query(Expression<Func<TEntity, bool>> whereExpression, string strOrderByFileds);
        Task<List<TEntity>> Query(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, object>> orderByExpression, bool isAsc = true);
        Task<List<TEntity>> Query(string strWhere, string strOrderByFileds);
        Task<List<TEntity>> Query(Expression<Func<TEntity, bool>> whereExpression, int intTop, string strOrderByFileds);
        Task<List<TEntity>> Query(string strWhere, int intTop, string strOrderByFileds);
        Task<List<TEntity>> Query(
            Expression<Func<TEntity, bool>> whereExpression, int intPageIndex, int intPageSize , string strOrderByFileds);
        Task<List<TEntity>> Query(string strWhere, int intPageIndex, int intPageSize , string strOrderByFileds);
        Task<List<TEntity>> QueryPage(Expression<Func<TEntity, bool>> whereExpression, int intPageIndex = 0, int intPageSize = 20, string strOrderByFileds = null);
    }

二、在Blog.Core.IRepository 層中,將其他的介面,繼承Base

  還記得前幾天我們一直用的IAdvertisementRepository.cs麼,終於可以卸到自身程式碼了,繼承Base

然後將其他所有的方法都繼承該基類方法,不細說,可以去Github檢視。

 三、在Blog.Core.Repository 層中,新增BASE資料夾,並新增 BaseRepository.cs 基類

基本寫法和前幾天的AdvertisementRepository.cs很類似,程式碼如下:

//BaseRepository.cs

namespace Blog.Core.Repository.Base
{
    public  class BaseRepository<TEntity> : IBaseRepository<TEntity> where TEntity : class, new()
    {
        private DbContext context;
        private SqlSugarClient db;
        private SimpleClient<TEntity> entityDB;

        public DbContext Context
        {
            get { return context; }
            set { context = value; }
        }
        internal SqlSugarClient Db
        {
            get { return db; }
            private set { db = value; }
        }
        internal SimpleClient<TEntity> EntityDB
        {
            get { return entityDB; }
            private set { entityDB = value; }
        }
        public BaseRepository()
        {
            DbContext.Init(BaseDBConfig.ConnectionString);
            context = DbContext.GetDbContext();
            db = context.Db;
            entityDB = context.GetEntityDB<TEntity>(db);
        }



        public async Task<TEntity> QueryByID(object objId)
        {
            return await Task.Run(() => db.Queryable<TEntity>().InSingle(objId));
        }
        /// <summary>
        /// 功能描述:根據ID查詢一條資料
        /// 作  者:Blog.Core
        /// </summary>
        /// <param name="objId">id(必須指定主鍵特性 [SugarColumn(IsPrimaryKey=true)]),如果是聯合主鍵,請使用Where條件</param>
        /// <param name="blnUseCache">是否使用快取</param>
        /// <returns>資料實體</returns>
        public async Task<TEntity> QueryByID(object objId, bool blnUseCache = false)
        {
            return await Task.Run(() => db.Queryable<TEntity>().WithCacheIF(blnUseCache).InSingle(objId));
        }

        /// <summary>
        /// 功能描述:根據ID查詢資料
        /// 作  者:Blog.Core
        /// </summary>
        /// <param name="lstIds">id列表(必須指定主鍵特性 [SugarColumn(IsPrimaryKey=true)]),如果是聯合主鍵,請使用Where條件</param>
        /// <returns>資料實體列表</returns>
        public async Task<List<TEntity>> QueryByIDs(object[] lstIds)
        {
            return await Task.Run(() => db.Queryable<TEntity>().In(lstIds).ToList());
        }

        /// <summary>
        /// 寫入實體資料
        /// </summary>
        /// <param name="entity">博文實體類</param>
        /// <returns></returns>
        public async Task<int> Add(TEntity entity)
        {
            var i = await Task.Run(() => db.Insertable(entity).ExecuteReturnBigIdentity());
            //返回的i是long型別,這裡你可以根據你的業務需要進行處理
            return (int)i;
        }

        /// <summary>
        /// 更新實體資料
        /// </summary>
        /// <param name="entity">博文實體類</param>
        /// <returns></returns>
        public async Task<bool> Update(TEntity entity)
        {
            //這種方式會以主鍵為條件
            var i = await Task.Run(() => db.Updateable(entity).ExecuteCommand());
            return i > 0;
        }

        public async Task<bool> Update(TEntity entity, string strWhere)
        {
            return await Task.Run(() => db.Updateable(entity).Where(strWhere).ExecuteCommand() > 0);
        }

        public async Task<bool> Update(string strSql, SugarParameter[] parameters = null)
        {
            return await Task.Run(() => db.Ado.ExecuteCommand(strSql, parameters) > 0);
        }

        public async Task<bool> Update(
          TEntity entity,
          List<string> lstColumns = null,
          List<string> lstIgnoreColumns = null,
          string strWhere = ""
            )
        {
            IUpdateable<TEntity> up = await Task.Run(() => db.Updateable(entity));
            if (lstIgnoreColumns != null && lstIgnoreColumns.Count > 0)
            {
                up = await Task.Run(() => up.IgnoreColumns(it => lstIgnoreColumns.Contains(it)));
            }
            if (lstColumns != null && lstColumns.Count > 0)
            {
                up = await Task.Run(() => up.UpdateColumns(it => lstColumns.Contains(it)));
            }
            if (!string.IsNullOrEmpty(strWhere))
            {
                up = await Task.Run(() => up.Where(strWhere));
            }
            return await Task.Run(() => up.ExecuteCommand()) > 0;
        }

        /// <summary>
        /// 根據實體刪除一條資料
        /// </summary>
        /// <param name="entity">博文實體類</param>
        /// <returns></returns>
        public async Task<bool> Delete(TEntity entity)
        {
            var i = await Task.Run(() => db.Deleteable(entity).ExecuteCommand());
            return i > 0;
        }

        /// <summary>
        /// 刪除指定ID的資料
        /// </summary>
        /// <param name="id">主鍵ID</param>
        /// <returns></returns>
        public async Task<bool> DeleteById(object id)
        {
            var i = await Task.Run(() => db.Deleteable<TEntity>(id).ExecuteCommand());
            return i > 0;
        }

        /// <summary>
        /// 刪除指定ID集合的資料(批量刪除)
        /// </summary>
        /// <param name="ids">主鍵ID集合</param>
        /// <returns></returns>
        public async Task<bool> DeleteByIds(object[] ids)
        {
            var i = await Task.Run(() => db.Deleteable<TEntity>().In(ids).ExecuteCommand());
            return i > 0;
        }



        /// <summary>
        /// 功能描述:查詢所有資料
        /// 作  者:Blog.Core
        /// </summary>
        /// <returns>資料列表</returns>
        public async Task<List<TEntity>> Query()
        {
            return await Task.Run(() => entityDB.GetList());
        }

        /// <summary>
        /// 功能描述:查詢資料列表
        /// 作  者:Blog.Core
        /// </summary>
        /// <param name="strWhere">條件</param>
        /// <returns>資料列表</returns>
        public async Task<List<TEntity>> Query(string strWhere)
        {
            return await Task.Run(() => db.Queryable<TEntity>().WhereIF(!string.IsNullOrEmpty(strWhere), strWhere).ToList());
        }

        /// <summary>
        /// 功能描述:查詢資料列表
        /// 作  者:Blog.Core
        /// </summary>
        /// <param name="whereExpression">whereExpression</param>
        /// <returns>資料列表</returns>
        public async Task<List<TEntity>> Query(Expression<Func<TEntity, bool>> whereExpression)
        {
            return await Task.Run(() => entityDB.GetList(whereExpression));
        }

        /// <summary>
        /// 功能描述:查詢一個列表
        /// 作  者:Blog.Core
        /// </summary>
        /// <param name="whereExpression">條件表示式</param>
        /// <param name="strOrderByFileds">排序欄位,如name asc,age desc</param>
        /// <returns>資料列表</returns>
        public async Task<List<TEntity>> Query(Expression<Func<TEntity, bool>> whereExpression, string strOrderByFileds)
        {
            return await Task.Run(() => db.Queryable<TEntity>().OrderByIF(!string.IsNullOrEmpty(strOrderByFileds), strOrderByFileds).WhereIF(whereExpression != null, whereExpression).ToList());
        }
        /// <summary>
        /// 功能描述:查詢一個列表
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <param name="orderByExpression"></param>
        /// <param name="isAsc"></param>
        /// <returns></returns>
        public async Task<List<TEntity>> Query(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, object>> orderByExpression, bool isAsc = true)
        {
            return await Task.Run(() => db.Queryable<TEntity>().OrderByIF(orderByExpression != null, orderByExpression, isAsc ? OrderByType.Asc : OrderByType.Desc).WhereIF(whereExpression != null, whereExpression).ToList());
        }

        /// <summary>
        /// 功能描述:查詢一個列表
        /// 作  者:Blog.Core
        /// </summary>
        /// <param name="strWhere">條件</param>
        /// <param name="strOrderByFileds">排序欄位,如name asc,age desc</param>
        /// <returns>資料列表</returns>
        public async Task<List<TEntity>> Query(string strWhere, string strOrderByFileds)
        {
            return await Task.Run(() => db.Queryable<TEntity>().OrderByIF(!string.IsNullOrEmpty(strOrderByFileds), strOrderByFileds).WhereIF(!string.IsNullOrEmpty(strWhere), strWhere).ToList());
        }


        /// <summary>
        /// 功能描述:查詢前N條資料
        /// 作  者:Blog.Core
        /// </summary>
        /// <param name="whereExpression">條件表示式</param>
        /// <param name="intTop">前N條</param>
        /// <param name="strOrderByFileds">排序欄位,如name asc,age desc</param>
        /// <returns>資料列表</returns>
        public async Task<List<TEntity>> Query(
            Expression<Func<TEntity, bool>> whereExpression,
            int intTop,
            string strOrderByFileds)
        {
            return await Task.Run(() => db.Queryable<TEntity>().OrderByIF(!string.IsNullOrEmpty(strOrderByFileds), strOrderByFileds).WhereIF(whereExpression != null, whereExpression).Take(intTop).ToList());
        }

        /// <summary>
        /// 功能描述:查詢前N條資料
        /// 作  者:Blog.Core
        /// </summary>
        /// <param name="strWhere">條件</param>
        /// <param name="intTop">前N條</param>
        /// <param name="strOrderByFileds">排序欄位,如name asc,age desc</param>
        /// <returns>資料列表</returns>
        public async Task<List<TEntity>> Query(
            string strWhere,
            int intTop,
            string strOrderByFileds)
        {
            return await Task.Run(() => db.Queryable<TEntity>().OrderByIF(!string.IsNullOrEmpty(strOrderByFileds), strOrderByFileds).WhereIF(!string.IsNullOrEmpty(strWhere), strWhere).Take(intTop).ToList());
        }

   

        /// <summary>
        /// 功能描述:分頁查詢
        /// 作  者:Blog.Core
        /// </summary>
        /// <param name="whereExpression">條件表示式</param>
        /// <param name="intPageIndex">頁碼(下標0)</param>
        /// <param name="intPageSize">頁大小</param>
        /// <param name="intTotalCount">資料總量</param>
        /// <param name="strOrderByFileds">排序欄位,如name asc,age desc</param>
        /// <returns>資料列表</returns>
        public async Task<List<TEntity>> Query(
            Expression<Func<TEntity, bool>> whereExpression,
            int intPageIndex,
            int intPageSize,
            string strOrderByFileds)
        {
            return await Task.Run(() => db.Queryable<TEntity>().OrderByIF(!string.IsNullOrEmpty(strOrderByFileds), strOrderByFileds).WhereIF(whereExpression != null, whereExpression).ToPageList(intPageIndex, intPageSize));
        }

        /// <summary>
        /// 功能描述:分頁查詢
        /// 作  者:Blog.Core
        /// </summary>
        /// <param name="strWhere">條件</param>
        /// <param name="intPageIndex">頁碼(下標0)</param>
        /// <param name="intPageSize">頁大小</param>
        /// <param name="intTotalCount">資料總量</param>
        /// <param name="strOrderByFileds">排序欄位,如name asc,age desc</param>
        /// <returns>資料列表</returns>
        public async Task<List<TEntity>> Query(
          string strWhere,
          int intPageIndex,
          int intPageSize,

          string strOrderByFileds)
        {
            return await Task.Run(() => db.Queryable<TEntity>().OrderByIF(!string.IsNullOrEmpty(strOrderByFileds), strOrderByFileds).WhereIF(!string.IsNullOrEmpty(strWhere), strWhere).ToPageList(intPageIndex, intPageSize));
        }

     


        public async Task<List<TEntity>> QueryPage(Expression<Func<TEntity, bool>> whereExpression,
        int intPageIndex = 0, int intPageSize = 20, string strOrderByFileds = null)
        {
            return await Task.Run(() => db.Queryable<TEntity>()
            .OrderByIF(!string.IsNullOrEmpty(strOrderByFileds), strOrderByFileds)
            .WhereIF(whereExpression != null, whereExpression)
            .ToPageList(intPageIndex, intPageSize));
        }




    }


}
View Code

然後呢,同樣在在Blog.Core.Repository 層中,將其他的介面,繼承BaseRepository,這裡略過,按下不表。

這裡要說下,昨天有人問我DbContext.cs內容講一下,其實呢,這個類裡,很簡單,主要是1、獲取SqlSugarClient例項,2、CodeFirst(根據實體類生成資料庫表);3、DbFirst(根據資料庫表生成實體類)。只不過都是用到的同名方法過載,可能看上去比較累,可以呼叫一次就能明白了。

這裡簡單說下DbFirst吧,其他的可以自行研究下,也可以右側掃碼加QQ群,我們一對一討論。DbFirst是一個根據資料庫表生成實體類的過程,前提是要有系統表的許可權,否則無法讀取表的結構,框架在底層封裝了很多模板,將真實值填充進去,特別像是動軟程式碼生成器或者T4模板。

四、同樣在Blog.Core.IServices 和 Blog.Core.Services 層中,分別新增基介面,並實現基類

    public interface IBaseServices<TEntity> where TEntity : class
    {

        Task<TEntity> QueryByID(object objId);
        Task<TEntity> QueryByID(object objId, bool blnUseCache = false);
        Task<List<TEntity>> QueryByIDs(object[] lstIds);

        Task<int> Add(TEntity model);

        Task<bool> DeleteById(object id);

        Task<bool> Delete(TEntity model);

        Task<bool> DeleteByIds(object[] ids);

        Task<bool> Update(TEntity model);
        Task<bool> Update(TEntity entity, string strWhere);

        Task<bool> Update(TEntity entity, List<string> lstColumns = null, List<string> lstIgnoreColumns = null, string strWhere = "");

        Task<List<TEntity>> Query();
        Task<List<TEntity>> Query(string strWhere);
        Task<List<TEntity>> Query(Expression<Func<TEntity, bool>> whereExpression);
        Task<List<TEntity>> Query(Expression<Func<TEntity, bool>> whereExpression, string strOrderByFileds);
        Task<List<TEntity>> Query(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, object>> orderByExpression, bool isAsc = true);
        Task<List<TEntity>> Query(string strWhere, string strOrderByFileds);

        Task<List<TEntity>> Query(Expression<Func<TEntity, bool>> whereExpression, int intTop, string strOrderByFileds);
        Task<List<TEntity>> Query(string strWhere, int intTop, string strOrderByFileds);

        Task<List<TEntity>> Query(
            Expression<Func<TEntity, bool>> whereExpression, int intPageIndex, int intPageSize, string strOrderByFileds);
        Task<List<TEntity>> Query(string strWhere, int intPageIndex, int intPageSize, string strOrderByFileds);


        Task<List<TEntity>> QueryPage(Expression<Func<TEntity, bool>> whereExpression, int intPageIndex = 0, int intPageSize = 20, string strOrderByFileds = null);
    }

//BaseServices.cs

namespace Blog.Core.Services.BASE
{
    public class BaseServices<TEntity> : IBaseServices<TEntity> where TEntity : class, new()
    {
        public IBaseRepository<TEntity> baseDal = new BaseRepository<TEntity>();

        public async Task<TEntity> QueryByID(object objId)
        {
            return await baseDal.QueryByID(objId);
        }
        /// <summary>
        /// 功能描述:根據ID查詢一條資料
        /// 作  者:AZLinli.Blog.Core
        /// </summary>
        /// <param name="objId">id(必須指定主鍵特性 [SugarColumn(IsPrimaryKey=true)]),如果是聯合主鍵,請使用Where條件</param>
        /// <param name="blnUseCache">是否使用快取</param>
        /// <returns>資料實體</returns>
        public async Task<TEntity> QueryByID(object objId, bool blnUseCache = false)
        {
            return await baseDal.QueryByID(objId, blnUseCache);
        }

        /// <summary>
        /// 功能描述:根據ID查詢資料
        /// 作  者:AZLinli.Blog.Core
        /// </summary>
        /// <param name="lstIds">id列表(必須指定主鍵特性 [SugarColumn(IsPrimaryKey=true)]),如果是聯合主鍵,請使用Where條件</param>
        /// <returns>資料實體列表</returns>
        public async Task<List<TEntity>> QueryByIDs(object[] lstIds)
        {
            return await baseDal.QueryByIDs(lstIds);
        }

        /// <summary>
        /// 寫入實體資料
        /// </summary>
        /// <param name="entity">博文實體類</param>
        /// <returns></returns>
        public async Task<int> Add(TEntity entity)
        {
            return await baseDal.Add(entity);
        }

        /// <summary>
        /// 更新實體資料
        /// </summary>
        /// <param name="entity">博文實體類</param>
        /// <returns></returns>
        public async Task<bool> Update(TEntity entity)
        {
            return await baseDal.Update(entity);
        }
        public async Task<bool> Update(TEntity entity, string strWhere)
        {
            return await baseDal.Update(entity, strWhere);
        }

        public async Task<bool> Update(
         TEntity entity,
         List<string> lstColumns = null,
         List<string> lstIgnoreColumns = null,
         string strWhere = ""
            )
        {
            return await baseDal.Update(entity, lstColumns, lstIgnoreColumns, strWhere);
        }


        /// <summary>
        /// 根據實體刪除一條資料
        /// </summary>
        /// <param name="entity">博文實體類</param>
        /// <returns></returns>
        public async Task<bool> Delete(TEntity entity)
        {
            return await baseDal.Delete(entity);
        }

        /// <summary>
        /// 刪除指定ID的資料
        /// </summary>
        /// <pa