前言
今天學習一個輕量級的ORM框架——SqlSugar
一、創建實體模型與數據庫
1、實體模型
創建Advertisement的實體模型,其他的相關模型,大家自行下載代碼即可:
public class Advertisement
{
/// <summary>
/// 主鍵
/// </summary>
public int Id { get; set; }
/// <summary>
/// 廣告圖片
/// </summary>
public string ImgUrl { get; set; }
/// <summary>
/// 廣告標題
/// </summary>
public string Title { get; set; }
/// <summary>
/// 廣告鏈接
/// </summary>
public string Url { get; set; }
/// <summary>
/// 備注
/// </summary>
public string Remark { get; set; }
/// <summary>
/// 創建時間
/// </summary>
public DateTime Createdate { get; set; } = DateTime.Now;
}
2、創建數據庫
這里采用的是MySql數據庫。sql語句在項目的Db文件夾。使用DBeaver來管理數據庫。這個是一個免費的數據庫管理工具。基本涵蓋了所有的數據庫類型。選擇Community Edition 社區版本。
當然,前提,需要先自行安裝MySql。建議安裝5.7以上的版本。
打開DBeaver,在Mysql數據庫類型,新建數據庫Blog,選擇字符類型為 utf8mb4,點擊確定創建空的數據庫:

在創建的Blog數據庫,右鍵 工具-Restore database,選擇sql文件,點擊開始進行數據庫恢復。

恢復完成之后

二、在 IRepository 層設計接口
倉儲接口 IAdvertisementRepository.cs 添加CURD四個接口,首先需要將Model層添加引用。
namespace Blog.Core.IRepository
{
public interface IAdvertisementRepository
{
int Sum(int i, int j);
int Add(Advertisement model);
bool Delete(Advertisement model);
bool Update(Advertisement model);
List<Advertisement> Query(Expression<Func<Advertisement, bool>> whereExpression);
}
}
三、在 Repository 層實現相應接口
在繼承的 IAdvertisementRepository點擊右鍵,選擇快速操作和重構,點擊實現接口。就可以快速創建需要實現的接口。
namespace Blog.Core.Repository
{
public class AdvertisementRepository : IAdvertisementRepository
{
public int Add(Advertisement model)
{
throw new NotImplementedException();
}
public bool Delete(Advertisement model)
{
throw new NotImplementedException();
}
public List<Advertisement> Query(Expression<Func<Advertisement, bool>> whereExpression)
{
throw new NotImplementedException();
}
public int Sum(int i, int j)
{
return i + j;
}
public bool Update(Advertisement model)
{
throw new NotImplementedException();
}
}
}
四、引用輕量級的ORM框架——SqlSugar
首先什么是ORM, 對象關系映射(Object Relational Mapping,簡稱ORM)模式是一種為了解決面向對象與關系數據庫存在的互不匹配的現象的技術。簡單的說,ORM是通過使用描述對象和數據庫之間映射的元數據,將程序中的對象自動持久化到關系數據庫中。
開始,我們需要先向 Repository 層中引入SqlSugar,
直接在類庫中通過Nuget引入 sqlSugarCore。

1、在Blog.Core.Repository新建一個sugar文件夾,然后添加兩個配置文件,BaseDBConfig.cs 和 DbContext.cs.
namespace Blog.Core.Repository.sugar
{
public class BaseDBConfig
{
//mysql的連接語句
public static string ConnectionString = "server=localhost;uid=root;pwd=admin;port=3306;database=blog;sslmode=Preferred;charset=utf8";
}
}
//DbContext.cs,一個詳細的上下文類
namespace Blog.Core.Repository.sugar
{
public class DbContext
{
private static string _connectionString;
private static DbType _dbType;
private SqlSugarClient _db;
/// <summary>
/// 連接字符串
/// Blog.Core
/// </summary>
public static string ConnectionString
{
get { return _connectionString; }
set { _connectionString = value; }
}
/// <summary>
/// 數據庫類型
/// Blog.Core
/// </summary>
public static DbType DbType
{
get { return _dbType; }
set { _dbType = value; }
}
/// <summary>
/// 數據連接對象
/// Blog.Core
/// </summary>
public SqlSugarClient Db
{
get { return _db; }
private set { _db = value; }
}
/// <summary>
/// 數據庫上下文實例(自動關閉連接)
/// Blog.Core
/// </summary>
public static DbContext Context
{
get
{
return new DbContext();
}
}
/// <summary>
/// 功能描述:構造函數
/// 作 者:Blog.Core
/// </summary>
private DbContext()
{
if (string.IsNullOrEmpty(_connectionString))
throw new ArgumentNullException("數據庫連接字符串為空");
_db = new SqlSugarClient(new ConnectionConfig()
{
ConnectionString = _connectionString,
DbType = _dbType,
IsAutoCloseConnection = true,
IsShardSameThread = true,
ConfigureExternalServices = new ConfigureExternalServices()
{
//DataInfoCacheService = new HttpRuntimeCache()
},
MoreSettings = new ConnMoreSettings()
{
//IsWithNoLockQuery = true,
IsAutoRemoveDataCache = true
}
});
}
/// <summary>
/// 功能描述:構造函數
/// 作 者:Blog.Core
/// </summary>
/// <param name="blnIsAutoCloseConnection">是否自動關閉連接</param>
private DbContext(bool blnIsAutoCloseConnection)
{
if (string.IsNullOrEmpty(_connectionString))
throw new ArgumentNullException("數據庫連接字符串為空");
_db = new SqlSugarClient(new ConnectionConfig()
{
ConnectionString = _connectionString,
DbType = _dbType,
IsAutoCloseConnection = blnIsAutoCloseConnection,
IsShardSameThread = true,
ConfigureExternalServices = new ConfigureExternalServices()
{
//DataInfoCacheService = new HttpRuntimeCache()
},
MoreSettings = new ConnMoreSettings()
{
//IsWithNoLockQuery = true,
IsAutoRemoveDataCache = true
}
});
}
#region 實例方法
/// <summary>
/// 功能描述:獲取數據庫處理對象
/// 作 者:Blog.Core
/// </summary>
/// <returns>返回值</returns>
public SimpleClient<T> GetEntityDB<T>() where T : class, new()
{
return new SimpleClient<T>(_db);
}
/// <summary>
/// 功能描述:獲取數據庫處理對象
/// 作 者:Blog.Core
/// </summary>
/// <param name="db">db</param>
/// <returns>返回值</returns>
public SimpleClient<T> GetEntityDB<T>(SqlSugarClient db) where T : class, new()
{
return new SimpleClient<T>(db);
}
#region 根據數據庫表生產實體類
/// <summary>
/// 功能描述:根據數據庫表生產實體類
/// 作 者:Blog.Core
/// </summary>
/// <param name="strPath">實體類存放路徑</param>
public void CreateClassFileByDBTalbe(string strPath)
{
CreateClassFileByDBTalbe(strPath, "Km.PosZC");
}
/// <summary>
/// 功能描述:根據數據庫表生產實體類
/// 作 者:Blog.Core
/// </summary>
/// <param name="strPath">實體類存放路徑</param>
/// <param name="strNameSpace">命名空間</param>
public void CreateClassFileByDBTalbe(string strPath, string strNameSpace)
{
CreateClassFileByDBTalbe(strPath, strNameSpace, null);
}
/// <summary>
/// 功能描述:根據數據庫表生產實體類
/// 作 者:Blog.Core
/// </summary>
/// <param name="strPath">實體類存放路徑</param>
/// <param name="strNameSpace">命名空間</param>
/// <param name="lstTableNames">生產指定的表</param>
public void CreateClassFileByDBTalbe(
string strPath,
string strNameSpace,
string[] lstTableNames)
{
CreateClassFileByDBTalbe(strPath, strNameSpace, lstTableNames, string.Empty);
}
/// <summary>
/// 功能描述:根據數據庫表生產實體類
/// 作 者:Blog.Core
/// </summary>
/// <param name="strPath">實體類存放路徑</param>
/// <param name="strNameSpace">命名空間</param>
/// <param name="lstTableNames">生產指定的表</param>
/// <param name="strInterface">實現接口</param>
public void CreateClassFileByDBTalbe(
string strPath,
string strNameSpace,
string[] lstTableNames,
string strInterface,
bool blnSerializable = false)
{
if (lstTableNames != null && lstTableNames.Length > 0)
{
_db.DbFirst.Where(lstTableNames).IsCreateDefaultValue().IsCreateAttribute()
.SettingClassTemplate(p => p = @"
{using}
namespace {Namespace}
{
{ClassDescription}{SugarTable}" + (blnSerializable ? "[Serializable]" : "") + @"
public partial class {ClassName}" + (string.IsNullOrEmpty(strInterface) ? "" : (" : " + strInterface)) + @"
{
public {ClassName}()
{
{Constructor}
}
{PropertyName}
}
}
")
.SettingPropertyTemplate(p => p = @"
{SugarColumn}
public {PropertyType} {PropertyName}
{
get
{
return _{PropertyName};
}
set
{
if(_{PropertyName}!=value)
{
base.SetValueCall(" + "\"{PropertyName}\",_{PropertyName}" + @");
}
_{PropertyName}=value;
}
}")
.SettingPropertyDescriptionTemplate(p => p = " private {PropertyType} _{PropertyName};\r\n" + p)
.SettingConstructorTemplate(p => p = " this._{PropertyName} ={DefaultValue};")
.CreateClassFile(strPath, strNameSpace);
}
else
{
_db.DbFirst.IsCreateAttribute().IsCreateDefaultValue()
.SettingClassTemplate(p => p = @"
{using}
namespace {Namespace}
{
{ClassDescription}{SugarTable}" + (blnSerializable ? "[Serializable]" : "") + @"
public partial class {ClassName}" + (string.IsNullOrEmpty(strInterface) ? "" : (" : " + strInterface)) + @"
{
public {ClassName}()
{
{Constructor}
}
{PropertyName}
}
}
")
.SettingPropertyTemplate(p => p = @"
{SugarColumn}
public {PropertyType} {PropertyName}
{
get
{
return _{PropertyName};
}
set
{
if(_{PropertyName}!=value)
{
base.SetValueCall(" + "\"{PropertyName}\",_{PropertyName}" + @");
}
_{PropertyName}=value;
}
}")
.SettingPropertyDescriptionTemplate(p => p = " private {PropertyType} _{PropertyName};\r\n" + p)
.SettingConstructorTemplate(p => p = " this._{PropertyName} ={DefaultValue};")
.CreateClassFile(strPath, strNameSpace);
}
}
#endregion
#region 根據實體類生成數據庫表
/// <summary>
/// 功能描述:根據實體類生成數據庫表
/// 作 者:Blog.Core
/// </summary>
/// <param name="blnBackupTable">是否備份表</param>
/// <param name="lstEntitys">指定的實體</param>
public void CreateTableByEntity<T>(bool blnBackupTable, params T[] lstEntitys) where T : class, new()
{
Type[] lstTypes = null;
if (lstEntitys != null)
{
lstTypes = new Type[lstEntitys.Length];
for (int i = 0; i < lstEntitys.Length; i++)
{
T t = lstEntitys[i];
lstTypes[i] = typeof(T);
}
}
CreateTableByEntity(blnBackupTable, lstTypes);
}
/// <summary>
/// 功能描述:根據實體類生成數據庫表
/// 作 者:Blog.Core
/// </summary>
/// <param name="blnBackupTable">是否備份表</param>
/// <param name="lstEntitys">指定的實體</param>
public void CreateTableByEntity(bool blnBackupTable, params Type[] lstEntitys)
{
if (blnBackupTable)
{
_db.CodeFirst.BackupTable().InitTables(lstEntitys); //change entity backupTable
}
else
{
_db.CodeFirst.InitTables(lstEntitys);
}
}
#endregion
#endregion
#region 靜態方法
/// <summary>
/// 功能描述:獲得一個DbContext
/// 作 者:Blog.Core
/// </summary>
/// <param name="blnIsAutoCloseConnection">是否自動關閉連接(如果為false,則使用接受時需要手動關閉Db)</param>
/// <returns>返回值</returns>
public static DbContext GetDbContext(bool blnIsAutoCloseConnection = true)
{
return new DbContext(blnIsAutoCloseConnection);
}
/// <summary>
/// 功能描述:設置初始化參數
/// 作 者:Blog.Core
/// </summary>
/// <param name="strConnectionString">連接字符串</param>
/// <param name="enmDbType">數據庫類型</param>
public static void Init(string strConnectionString, DbType enmDbType = SqlSugar.DbType.SqlServer)
{
_connectionString = strConnectionString;
_dbType = enmDbType;
}
/// <summary>
/// 功能描述:創建一個鏈接配置
/// 作 者:Blog.Core
/// </summary>
/// <param name="blnIsAutoCloseConnection">是否自動關閉連接</param>
/// <param name="blnIsShardSameThread">是否誇類事務</param>
/// <returns>ConnectionConfig</returns>
public static ConnectionConfig GetConnectionConfig(bool blnIsAutoCloseConnection = true, bool blnIsShardSameThread = false)
{
ConnectionConfig config = new ConnectionConfig()
{
ConnectionString = _connectionString,
DbType = _dbType,
IsAutoCloseConnection = blnIsAutoCloseConnection,
ConfigureExternalServices = new ConfigureExternalServices()
{
//DataInfoCacheService = new HttpRuntimeCache()
},
IsShardSameThread = blnIsShardSameThread
};
return config;
}
/// <summary>
/// 功能描述:獲取一個自定義的DB
/// 作 者:Blog.Core
/// </summary>
/// <param name="config">config</param>
/// <returns>返回值</returns>
public static SqlSugarClient GetCustomDB(ConnectionConfig config)
{
return new SqlSugarClient(config);
}
/// <summary>
/// 功能描述:獲取一個自定義的數據庫處理對象
/// 作 者:Blog.Core
/// </summary>
/// <param name="sugarClient">sugarClient</param>
/// <returns>返回值</returns>
public static SimpleClient<T> GetCustomEntityDB<T>(SqlSugarClient sugarClient) where T : class, new()
{
return new SimpleClient<T>(sugarClient);
}
/// <summary>
/// 功能描述:獲取一個自定義的數據庫處理對象
/// 作 者:Blog.Core
/// </summary>
/// <param name="config">config</param>
/// <returns>返回值</returns>
public static SimpleClient<T> GetCustomEntityDB<T>(ConnectionConfig config) where T : class, new()
{
SqlSugarClient sugarClient = GetCustomDB(config);
return GetCustomEntityDB<T>(sugarClient);
}
#endregion
}
}

2、修改數據連接字符串,這樣以后就可以在AppSettings配置連接
a、在appsettings.json 中添加
"AppSettings": {
"MysqlConnection": "server=localhost;uid=root;pwd=admin;port=3306;database=blog;sslmode=Preferred;charset=utf8",
"Database": "BlogCoreDb"
},
b、在 startup.cs 中的 ConfigureServices() 方法中添加
//數據庫配置
BaseDBConfig.ConnectionString = Configuration.GetSection("AppSettings:MysqlConnection").Value;
c、修改BaseDBConfig.cs
public static string ConnectionString { get; set; }
3、然后在剛剛我們實現那四個方法的AdvertisementRepository.cs中,重寫構造函數,編輯統一Sqlsugar實例方法,用到了私有屬性,為以后的單列模式做准備。最終的倉儲持久化是:
namespace Blog.Core.Repository
{
public class AdvertisementRepository : IAdvertisementRepository
{
private DbContext context;
private SqlSugarClient db;
private SimpleClient<Advertisement> entityDB;
internal SqlSugarClient Db
{
get { return db; }
private set { db = value; }
}
public DbContext Context
{
get { return context; }
set { context = value; }
}
public AdvertisementRepository()
{
DbContext.Init(BaseDBConfig.ConnectionString);
DbContext.DbType = DbType.MySql;
context = DbContext.GetDbContext();
db = context.Db;
entityDB = context.GetEntityDB<Advertisement>(db);
}
public int Add(Advertisement model)
{
//返回的i是long類型,這里你可以根據你的業務需要進行處理
var i = db.Insertable(model).ExecuteReturnBigIdentity();
return i.ObjToInt();
}
public bool Delete(Advertisement model)
{
var i = db.Deleteable(model).ExecuteCommand();
return i > 0;
}
public List<Advertisement> Query(Expression<Func<Advertisement, bool>> whereExpression)
{
return entityDB.GetList(whereExpression);
}
public int Sum(int i, int j)
{
return i + j;
}
public bool Update(Advertisement model)
{
//這種方式會以主鍵為條件
var i = db.Updateable(model).ExecuteCommand();
return i > 0;
}
}
}
4、正式開始寫持久化邏輯代碼(注意:我在Model層中,添加了全局的數據類型轉換方法,UtilConvert,這樣就不用每次都Convert,而且也解決了為空轉換異常的bug)
namespace Blog.Core.Model.Helper
{
public static class UtilConvert
{
/// <summary>
///
/// </summary>
/// <param name="thisValue"></param>
/// <returns></returns>
public static int ObjToInt(this object thisValue)
{
int reval = 0;
if (thisValue == null) return 0;
if (thisValue != null && thisValue != DBNull.Value && int.TryParse(thisValue.ToString(), out reval))
{
return reval;
}
return reval;
}
/// <summary>
///
/// </summary>
/// <param name="thisValue"></param>
/// <param name="errorValue"></param>
/// <returns></returns>
public static int ObjToInt(this object thisValue, int errorValue)
{
int reval = 0;
if (thisValue != null && thisValue != DBNull.Value && int.TryParse(thisValue.ToString(), out reval))
{
return reval;
}
return errorValue;
}
/// <summary>
///
/// </summary>
/// <param name="thisValue"></param>
/// <returns></returns>
public static double ObjToMoney(this object thisValue)
{
double reval = 0;
if (thisValue != null && thisValue != DBNull.Value && double.TryParse(thisValue.ToString(), out reval))
{
return reval;
}
return 0;
}
/// <summary>
///
/// </summary>
/// <param name="thisValue"></param>
/// <param name="errorValue"></param>
/// <returns></returns>
public static double ObjToMoney(this object thisValue, double errorValue)
{
double reval = 0;
if (thisValue != null && thisValue != DBNull.Value && double.TryParse(thisValue.ToString(), out reval))
{
return reval;
}
return errorValue;
}
/// <summary>
///
/// </summary>
/// <param name="thisValue"></param>
/// <returns></returns>
public static string ObjToString(this object thisValue)
{
if (thisValue != null) return thisValue.ToString().Trim();
return "";
}
/// <summary>
///
/// </summary>
/// <param name="thisValue"></param>
/// <param name="errorValue"></param>
/// <returns></returns>
public static string ObjToString(this object thisValue, string errorValue)
{
if (thisValue != null) return thisValue.ToString().Trim();
return errorValue;
}
/// <summary>
///
/// </summary>
/// <param name="thisValue"></param>
/// <returns></returns>
public static Decimal ObjToDecimal(this object thisValue)
{
Decimal reval = 0;
if (thisValue != null && thisValue != DBNull.Value && decimal.TryParse(thisValue.ToString(), out reval))
{
return reval;
}
return 0;
}
/// <summary>
///
/// </summary>
/// <param name="thisValue"></param>
/// <param name="errorValue"></param>
/// <returns></returns>
public static Decimal ObjToDecimal(this object thisValue, decimal errorValue)
{
Decimal reval = 0;
if (thisValue != null && thisValue != DBNull.Value && decimal.TryParse(thisValue.ToString(), out reval))
{
return reval;
}
return errorValue;
}
/// <summary>
///
/// </summary>
/// <param name="thisValue"></param>
/// <returns></returns>
public static DateTime ObjToDate(this object thisValue)
{
DateTime reval = DateTime.MinValue;
if (thisValue != null && thisValue != DBNull.Value && DateTime.TryParse(thisValue.ToString(), out reval))
{
reval = Convert.ToDateTime(thisValue);
}
return reval;
}
/// <summary>
///
/// </summary>
/// <param name="thisValue"></param>
/// <param name="errorValue"></param>
/// <returns></returns>
public static DateTime ObjToDate(this object thisValue, DateTime errorValue)
{
DateTime reval = DateTime.MinValue;
if (thisValue != null && thisValue != DBNull.Value && DateTime.TryParse(thisValue.ToString(), out reval))
{
return reval;
}
return errorValue;
}
/// <summary>
///
/// </summary>
/// <param name="thisValue"></param>
/// <returns></returns>
public static bool ObjToBool(this object thisValue)
{
bool reval = false;
if (thisValue != null && thisValue != DBNull.Value && bool.TryParse(thisValue.ToString(), out reval))
{
return reval;
}
return reval;
}
}
}
五、在 IServices 層設計服務接口,並 Service 層實現
namespace Blog.Core.IService
{
public interface IAdvertisementServices
{
int Sum(int i, int j);
int Add(Advertisement model);
bool Delete(Advertisement model);
bool Update(Advertisement model);
List<Advertisement> Query(Expression<Func<Advertisement, bool>> whereExpression);
}
}
namespace Blog.Core.Service
{
public class AdvertisementServices : IAdvertisementServices
{
public IAdvertisementRepository dal = new AdvertisementRepository();
public int Sum(int i, int j)
{
return dal.Sum(i, j);
}
public int Add(Advertisement model)
{
return dal.Add(model);
}
public bool Delete(Advertisement model)
{
return dal.Delete(model);
}
public List<Advertisement> Query(Expression<Func<Advertisement, bool>> whereExpression)
{
return dal.Query(whereExpression);
}
public bool Update(Advertisement model)
{
return dal.Update(model);
}
}
}
六、Controller測試接口
新增一個Get方法,根據id獲取信息
// GET: api/Blog/5
/// <summary>
///
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet("{id}", Name = "Get")]
public List<Advertisement> Get(int id)
{
IAdvertisementServices advertisementServices = new AdvertisementServices();
return advertisementServices.Query(d => d.Id == id);
}
接下來運行調試,在我們接口文檔中,直接點擊調試.得到的結果返回結果http代碼是200

結語
今天簡單的了解了什么是ORM,以及其中的SqlSugar,然后呢,倉儲模式的具體使用,最后還有真正的連接數據庫,獲取到數據。
