net core Webapi基礎工程搭建(六)——數據庫操作_Part 1


前言

后端開發最常打交道的就是數據庫了(靜態網站靠邊),上一篇net core Webapi基礎工程搭建(五)——緩存機制,緩存就是為了減少數據庫的讀操作,不過什么訪問都是會耗時的,拿空間(內存)換時間對用戶體驗來說是慣用手段,后續介紹界面操作的時候再說用戶體驗。

SqlSugar

當然你可以用EF(太重,擴展性相對差,但不可否認基本上涵蓋范圍夠廣),也可以用Dapper(這個我之前頭一回鼓搗net core的時候用的是Dapper),或者自己基於原生去寫數據庫的操作,都Ok,但是如果有造好的輪子,對於我們來說用就行了,可以深入理解但對於常規開發來說,CV大法是最好的(新手向),SqlSugar文檔地址

之前的工程在最初創建的時候,沒有創建完整,因為當時不操作數據層,所以偷個懶,這次一並創建,具體過程不再贅述
,同April.Util工程的創建一致,都是類庫項目,新建April.ServiceApril.Entity

好了,我們在Service與Entity項目中通過NuGet包引入sqlSugarCore,至於原因前面也說過net core Webapi基礎工程搭建(四)——日志功能log4net

這里應該不需要再圖文介紹引入了,如果不清楚,也可以去上面的鏈接查看NuGet的引入方法。

引入完成后,我們在Entity項目創建一個類對象,命名為StudentEntity吧,只是做個示例。

    public class StudentEntity
    {
        private int _ID = -1;
        private string _Name = string.Empty;
        private string _Number = string.Empty;
        private int _Age = 0;
        private int _Sex = 0;
        private string _Address = string.Empty;
    }

對象屬性這塊兒,看個人習慣,有些人偏向於直接get,set方法,我習慣於先初始化,選中所有的私有屬性,使用宇宙第一IDE的快捷鍵Ctrl+R+E,點擊確定,好了自己去加注釋去吧。

神器的好處
這里也說下為什么Entity這個實例對象層也要引入SqlSugar,是因為如果你的表名或者屬性名與數據庫不一致的時候,還是需要標識出來的,比如下面的代碼,具體的用法還是去參考文檔吧,我這只是輕描淡寫下。

	[SugarTable("test_Student")]
    public class StudentEntity
    {
        private int _ID = -1;
        private string _Name = string.Empty;
        private string _Number = string.Empty;
        private int _Age = 0;
        private int _Sex = 0;
        private string _Address = string.Empty;

        /// <summary>
        /// 主鍵
        /// </summary>
        [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
        public int ID { get => _ID; set => _ID = value; }
        /// <summary>
        /// 姓名
        /// </summary>
        public string Name { get => _Name; set => _Name = value; }
        /// <summary>
        /// 學號
        /// </summary>
        public string Number { get => _Number; set => _Number = value; }
        /// <summary>
        /// 年齡
        /// </summary>
        public int Age { get => _Age; set => _Age = value; }
        /// <summary>
        /// 性別
        /// </summary>
        public int Sex { get => _Sex; set => _Sex = value; }
        /// <summary>
        /// 家庭住址
        /// </summary>
        [SugarColumn(ColumnName = "test_Address")]
        public string Address { get => _Address; set => _Address = value; }
    }

實體對象我就不多寫了,重復的工作是根據你自己的業務所處理的。

Service層

這個地方我重點標注下,是因為數據庫這塊兒的操作還是需要重視的,我們先來新建個BaseDbContext用於執行數據庫操作的實體。

	public class BaseDbContext
    {
        public SqlSugarClient Db;
        /// <summary>
        /// 構造函數
        /// </summary>
        /// <param name="connStr">數據庫連接串</param>
        /// <param name="sqlType">數據庫類型</param>
        public BaseDbContext(string connStr, int sqlType = 1)
        {
            InitDataBase(connStr, sqlType);
        }

        /// <summary>
        /// 構造函數
        /// </summary>
        /// <param name="serverIp">服務器IP</param>
        /// <param name="user">用戶名</param>
        /// <param name="pass">密碼</param>
        /// <param name="dataBase">數據庫</param>
        public BaseDbContext(string serverIp, string user, string pass, string dataBase)
        {
            string connStr = $"server={serverIp};user id={user};password={pass};persistsecurityinfo=True;database={dataBase}";
            InitDataBase(connStr);
        }

        /// <summary>
        /// 初始化數據庫連接
        /// </summary>
        /// <param name="listConn">連接字符串</param>
        private void InitDataBase(string connStr, int sqlType = 1)
        {
            Db = new SqlSugarClient(new ConnectionConfig()
            {
                ConnectionString = connStr,
                DbType = (DbType)sqlType,
                IsAutoCloseConnection = true,
                //SlaveConnectionConfigs = slaveConnectionConfigs
            });
            Db.Ado.CommandTimeOut = 30000;//設置超時時間
            Db.Aop.OnLogExecuted = (sql, pars) => //SQL執行完事件
            {
                //這里可以查看執行的sql語句跟參數
            };
            Db.Aop.OnLogExecuting = (sql, pars) => //SQL執行前事件
            {
                //這里可以查看執行的sql語句跟參數
            };
            Db.Aop.OnError = (exp) =>//執行SQL 錯誤事件
            {
                //這里可以查看執行的sql語句跟參數
            };
            Db.Aop.OnExecutingChangeSql = (sql, pars) => //SQL執行前 可以修改SQL
            {
                return new KeyValuePair<string, SugarParameter[]>(sql, pars);
            };
        }
        /// <summary>
        /// 開啟事務
        /// </summary>
        public void BeginTran()
        {
            Db.Ado.BeginTran();
        }
        /// <summary>
        /// 提交事務
        /// </summary>
        public void CommitTran()
        {
            Db.Ado.CommitTran();
        }
        /// <summary>
        /// 回滾事務
        /// </summary>
        public void RollbackTran()
        {
            Db.Ado.RollbackTran();
        }
    }

構造函數主要用於實例化你的數據庫對象(連接串,數據庫類型),日志的記錄,事務這些也都標注上,后續可以替換直接使用。

BaseService(基類)

在最初寫net core的時候,我用Repository層來實現sql處理,Service用來做邏輯處理,傳統的三層架構,但是對於簡單的工程來說,個人感覺Bll層的存在不是那么理想,可能是我沒徹底理解三層架構吧,這個地方如果有個人想法或好的見解也希望一塊交流,互相進步。

在寫基類之前,我們在Util層新建一個SqlSqlFilterEntity,這步可能算是多此一舉,但是為了減少團隊其他人的學習成本,我還是寫了這個對象,以致於后續的封裝,會以此為參數做傳遞而不公開lambda的寫法使用。

    public class SqlFilterEntity
    {
        private string _Filter = string.Empty;
        private Dictionary<string, object> _Value = null;
        /// <summary>
        /// 查詢條件
        /// </summary>
        public string Filter { get => _Filter; set => _Filter = value; }
        /// <summary>
        /// 查詢參數
        /// </summary>
        public Dictionary<string, object> Value { get => _Value; set => _Value = value; }
    }

在Service層新建IBaseService接口。

    public interface IBaseService<T> : IDisposable
    {
        /// <summary>
        /// 分頁查詢集合
        /// </summary>
        /// <param name="pageIndex">頁碼</param>
        /// <param name="pageSize">分頁大小</param>
        /// <param name="strField">查詢字段</param>
        /// <param name="filter">查詢條件</param>
        /// <param name="strOrder">排序規則</param>
        /// <param name="totalCount">總數</param>
        /// <returns>數據集合</returns>
        List<T> GetPageList(int pageIndex, int pageSize, string strField, SqlFilterEntity filter, string strOrder, out int totalCount);

        /// <summary>
        /// 獲取列表集合
        /// </summary>
        /// <param name="field">查詢字段</param>
        /// <param name="filter">查詢條件</param>
        /// <returns>數據集合</returns>
        ISugarQueryable<T> GetList(string field, SqlFilterEntity filter);

        /// <summary>
        /// 獲取列表集合
        /// </summary>
        /// <returns>數據集合</returns>
        ISugarQueryable<T> GetList(int top = 0);

        /// <summary>
        /// 獲取對象
        /// </summary>
        /// <param name="field">查詢字段</param>
        /// <param name="filter">查詢條件</param>
        /// <returns>對象</returns>
        T GetEntity(SqlFilterEntity filter, string field = "");

        /// <summary>
        /// 判斷數據是否存在
        /// </summary>
        /// <param name="filter">查詢條件</param>
        /// <returns>執行結果</returns>
        bool IsExists(SqlFilterEntity filter);

        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="entity">實例對象</param>
        /// <param name="ignoreColumns">排除列</param>
        /// <param name="isLock">是否加鎖</param>
        /// <returns>自增id</returns>
        int Insert(T entity, List<string> ignoreColumns = null, bool isLock = false);

        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="entity">實例對象</param>
        /// <param name="ignoreColumns">排除列</param>
        /// <param name="isLock">是否加鎖</param>
        /// <returns>執行結果</returns>
        bool Update(T entity, List<string> ignoreColumns = null, bool isLock = false);

        /// <summary>
        /// 根據主鍵刪除
        /// </summary>
        /// <param name="entity">實例對象</param>
        /// <param name="isLock">是否加鎖</param>
        /// <returns>執行結果</returns>
        bool Delete(T entity, bool isLock = false);

    }

可以看到,我通過SqlFilterEntity這一實例來傳遞我的Where條件。

實現接口方法,新建BaseService

    public class BaseService<T> : IBaseService<T> where T : class, new()
    {
        private BaseDbContext baseDb;
        protected SqlSugarClient db;

        public BaseService()
        {
            baseDb = new BaseDbContext("你的數據庫連接");
            db = baseDb.Db;
        }

        /// <summary>
        /// 分頁查詢集合
        /// </summary>
        /// <param name="pageIndex">頁碼</param>
        /// <param name="pageSize">分頁大小</param>
        /// <param name="strField">查詢字段</param>
        /// <param name="filter">查詢條件</param>
        /// <param name="strOrder">排序規則</param>
        /// <param name="totalCount">總數</param>
        /// <returns>數據集合</returns>
        public List<T> GetPageList(int pageIndex, int pageSize, string strField, SqlFilterEntity filter, string strOrder, out int totalCount)
        {
            totalCount = 0;
            if (pageIndex <= 0)
            {
                pageIndex = 1;
            }
            if (pageSize <= 0)
            {
                pageSize = 10;//暫定默認分頁大小為10
            }
            if (string.IsNullOrEmpty(strField))
            {
                strField = "";
            }
            if (string.IsNullOrEmpty(strOrder))
            {
                strOrder = string.Format("ID asc");//這個地方我當時是在Config設置默認的排序
            }
            if (filter == null)
            {
                filter = new SqlFilterEntity();
            }
            return db.Queryable<T>().With(SqlWith.NoLock).Select(strField).WhereIF(!string.IsNullOrEmpty(filter.Filter), filter.Filter, filter.Value).OrderByIF(!string.IsNullOrEmpty(strOrder), strOrder).ToPageList(pageIndex, pageSize, ref totalCount);
        }

        /// <summary>
        /// 獲取列表集合
        /// </summary>
        /// <param name="field">查詢字段</param>
        /// <param name="filter">查詢條件</param>
        /// <returns>數據集合</returns>
        public ISugarQueryable<T> GetList(string field, SqlFilterEntity filter)
        {
            if (string.IsNullOrEmpty(field))
            {
                field = "";
            }
            if (filter == null)
            {
                filter = new SqlFilterEntity();
            }
            return db.Queryable<T>().With(SqlWith.NoLock).Select(field).WhereIF(!string.IsNullOrEmpty(filter.Filter), filter.Filter, filter.Value);
        }

        /// <summary>
        /// 獲取列表集合
        /// </summary>
        /// <returns>數據集合</returns>
        public ISugarQueryable<T> GetList(int top = 0)
        {
            if (top > 0)
            {
                return db.Queryable<T>().With(SqlWith.NoLock).Take(top);
            }
            else
            {
                return db.Queryable<T>().With(SqlWith.NoLock);
            }
        }

        /// <summary>
        /// 獲取對象
        /// </summary>
        /// <param name="field">查詢字段</param>
        /// <param name="filter">查詢條件</param>
        /// <returns>對象</returns>
        public T GetEntity(SqlFilterEntity filter, string field = "")
        {
            if (string.IsNullOrEmpty(field))
            {
                field = "";
            }
            if (filter != null)
            {
                return db.Queryable<T>().With(SqlWith.NoLock).Select(field).WhereIF(!string.IsNullOrEmpty(filter.Filter), filter.Filter, filter.Value).First();
            }
            return default(T);
        }

        /// <summary>
        /// 判斷數據是否存在
        /// </summary>
        /// <param name="filter">查詢條件</param>
        /// <returns>執行結果</returns>
        public bool IsExists(SqlFilterEntity filter)
        {
            var result = db.Queryable<T>().With(SqlWith.NoLock).WhereIF(!string.IsNullOrEmpty(filter.Filter), filter.Filter, filter.Value).Count();
            return result > 0;
        }

        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="entity">實例對象</param>
        /// <param name="ignoreColumns">排除列</param>
        /// <param name="isLock">是否加鎖</param>
        /// <returns>自增id</returns>
        public int Insert(T entity, List<string> ignoreColumns = null, bool isLock = false)
        {
            if (ignoreColumns == null)
            {
                ignoreColumns = new List<string>();
            }
            var result = isLock ?
                db.Insertable(entity).With(SqlWith.UpdLock).IgnoreColumns(ignoreColumns.ToArray()).ExecuteReturnIdentity()
                : db.Insertable(entity).IgnoreColumns(ignoreColumns.ToArray()).ExecuteReturnIdentity();
            return result;
        }


        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="entity">實例對象</param>
        /// <param name="ignoreColumns">排除列</param>
        /// <param name="isLock">是否加鎖</param>
        /// <returns>執行結果</returns>
        public bool Update(T entity, List<string> ignoreColumns = null, bool isLock = false)
        {
            if (ignoreColumns == null)
            {
                ignoreColumns = new List<string>();
            }
            var result = isLock ?
                db.Updateable(entity).With(SqlWith.UpdLock).IgnoreColumns(ignoreColumns.ToArray()).ExecuteCommand()
                : db.Updateable(entity).IgnoreColumns(ignoreColumns.ToArray()).ExecuteCommand();
            return result > 0;
        }

        /// <summary>
        /// 根據主鍵刪除
        /// </summary>
        /// <param name="entity">實例對象</param>
        /// <param name="isLock">是否加鎖</param>
        /// <returns>執行結果</returns>
        public bool Delete(T entity, bool isLock = false)
        {
            var result = isLock ?
                db.Deleteable<T>(entity).With(SqlWith.RowLock).ExecuteCommand().ObjToBool()
                : db.Deleteable<T>(entity).ExecuteCommand().ObjToBool();
            return result;
        }

        public void Dispose()
        {

        }
    }

小結

這一篇感覺寫的不多,但是代碼放的有點兒多,習慣性的把東西盡可能介紹詳細點兒,萬一有人真的從小白開始一點點兒想折騰個啥東西呢(比如說我),下一篇Part 2介紹具體的用法和測試吧。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM