前言
后端開發最常打交道的就是數據庫了(靜態網站靠邊),上一篇net core Webapi基礎工程搭建(五)——緩存機制,緩存就是為了減少數據庫的讀操作,不過什么訪問都是會耗時的,拿空間(內存)換時間對用戶體驗來說是慣用手段,后續介紹界面操作的時候再說用戶體驗。
SqlSugar
當然你可以用EF(太重,擴展性相對差,但不可否認基本上涵蓋范圍夠廣),也可以用Dapper(這個我之前頭一回鼓搗net core的時候用的是Dapper),或者自己基於原生去寫數據庫的操作,都Ok,但是如果有造好的輪子,對於我們來說用就行了,可以深入理解但對於常規開發來說,CV大法是最好的(新手向),SqlSugar的文檔地址。
之前的工程在最初創建的時候,沒有創建完整,因為當時不操作數據層,所以偷個懶,這次一並創建,具體過程不再贅述
,同April.Util工程的創建一致,都是類庫項目,新建April.Service,April.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介紹具體的用法和測試吧。