話說C#程式員人手一個ORM,確實沒有必要再寫ORM了,不過我的ORM并不是新的,是從DBHelper演化過來的,算是DBHelper魔改版,
目前流行的ORM有EF、Dapper、SqlSugar、FreeSql、Chloe等,有經驗的程式員總是在這些ORM基礎上或者在DBHelper基礎上再封裝一套,再加上自己寫ORM的,可謂人手一套ORM,可能是因為在框架當中,撰寫ORM,入門相對簡單吧,但是做好很難,
本專案來源:專案來源于需求,2014年我在上家公司做ERP、CRM之類的BS管理系統專案,當時公司用的就是OracleHelper、SqlServerHelper之類的;2015年開始嘗試修改,當時支持了事務,但仍是靜態的幫助類;2016年我把OracleHelper、SqlServerHelper、MySqlHelper、SQLiteHelper合成了一個DBHelper,仍是靜態類,2017跳槽到現公司,公司大專案我的DBHelper就用不上了,平時小專案用用;2020年,終于發現靜態DBHelper多執行緒并發,事務這塊有BUG,所以改造成了非靜態的,后來又加入SqlString類,重構以方便擴展支持更多資料庫種類;最近簡單支持了一下Lambda運算式;幾經修改,原來DBHelper的那些方法幾乎沒怎么變;長期不變的穩定的API才是好API,
主要是自己用的,如果別人要用的話,建議從gitee或github上拉原始碼下來,原始碼在手好控制,原始碼相對簡單,有經驗的程式員不難看懂,可以自己除錯修改擴展,Lambda運算式是新支持的,如果Lambda hold不住,就使用原生SQL,
跟主流ORM相比還是比較欠缺的,它只是一個DBHelper,
原始碼地址(VS2015、.NET Framework 4.5.2):
https://gitee.com/s0611163/DBHelper
https://github.com/0611163/DBHelper
.NET Core 5 版本原始碼地址(VS2019、.NET 5):
https://gitee.com/s0611163/DBHelperCore
該ORM介紹及使用示例如下:
DBHelper
簡介
一款輕量級ORM,查詢使用原生SQL,查詢結果映射到物體類,增刪改支持物體類,支持Oracle、MSSQL、MySQL、SQLite等多種資料庫,有配套Model生成器,方便自己擴展以支持更多資料庫
特點
- 支持Oracle、MSSQL、MySQL、SQLite四種資料庫
- 方便擴展以支持更多關系資料庫
- 有配套的Model生成器
- insert、update、delete操作無需寫SQL
- 查詢使用原生SQL
- 查詢結果通過映射轉成物體類或物體類集合
- 支持引數化查詢,通過SqlString類提供非常方便的引數化查詢
- 支持連接多個資料源
- 單表查詢、單表分頁查詢、簡單的聯表分頁查詢支持Lambda運算式
- 支持原生SQL和Lambda運算式混寫
優點
- 代碼實作比較簡單,有經驗的程式員容易掌控代碼,自己修改和擴展
- 查詢使用原生SQL
缺點
- 聯表查詢對Lambda運算式的支持比較弱
- 復雜查詢不支持Lambda運算式
建議
- 單表查詢可以使用Lambda運算式
- 聯表查詢以及復雜查詢建議使用原生SQL或原生SQL和Lambda運算式混寫
作者郵箱
[email protected]
示例
定義資料庫物件
public class DBHelper
{
#region 變數
private static ISessionHelper _sessionHelper = new SessionHelper(ConfigurationManager.ConnectionStrings["DefaultConnection"].ToString(), DBType.MySQL);
#endregion
#region 獲取 ISession
/// <summary>
/// 獲取 ISession
/// </summary>
public static ISession GetSession()
{
return _sessionHelper.GetSession();
}
#endregion
#region 獲取 ISession (異步)
/// <summary>
/// 獲取 ISession (異步)
/// </summary>
public static async Task<ISession> GetSessionAsync()
{
return await _sessionHelper.GetSessionAsync();
}
#endregion
}
使用Model生成器生成物體類
- 物體類放在Models檔案夾中
- 擴展物體類放在ExtModels檔案夾中
- 物體類和擴展物體類使用partial修飾,實際上是一個類,放在不同的檔案中
- 如果需要添加自定義屬性,請修改ExtModels,不要修改Models
物體類示例
/// <summary>
/// 訂單表
/// </summary>
[Serializable]
[DBTable("bs_order")]
public partial class BsOrder
{
/// <summary>
/// 主鍵
/// </summary>
[DBKey]
[DBField]
public string Id { get; set; }
/// <summary>
/// 訂單時間
/// </summary>
[DBField("order_time")]
public DateTime OrderTime { get; set; }
/// <summary>
/// 訂單金額
/// </summary>
[DBField]
public decimal? Amount { get; set; }
/// <summary>
/// 下單用戶
/// </summary>
[DBField("order_userid")]
public long OrderUserid { get; set; }
/// <summary>
/// 訂單狀態(0草稿 1已下單 2已付款 3已發貨 4完成)
/// </summary>
[DBField]
public int Status { get; set; }
/// <summary>
/// 備注
/// </summary>
[DBField]
public string Remark { get; set; }
/// <summary>
/// 創建者ID
/// </summary>
[DBField("create_userid")]
public string CreateUserid { get; set; }
/// <summary>
/// 創建時間
/// </summary>
[DBField("create_time")]
public DateTime CreateTime { get; set; }
/// <summary>
/// 更新者ID
/// </summary>
[DBField("update_userid")]
public string UpdateUserid { get; set; }
/// <summary>
/// 更新時間
/// </summary>
[DBField("update_time")]
public DateTime? UpdateTime { get; set; }
}
修改擴展物體類
- 修改擴展物體類,添加自定義屬性
- 下面的擴展物體類中,查詢時OrderUserRealName會被自動填充,查詢SQL:select t.*, u.real_name as OrderUserRealName from ......
- DetailList不會被自動填充,需要手動查詢
擴展物體類示例
/// <summary>
/// 訂單表
/// </summary>
public partial class BsOrder
{
/// <summary>
/// 訂單明細集合
/// </summary>
public List<BsOrderDetail> DetailList { get; set; }
/// <summary>
/// 下單用戶姓名
/// </summary>
public string OrderUserRealName { get; set; }
/// <summary>
/// 下單用戶名
/// </summary>
public string OrderUserName { get; set; }
}
添加
public void Insert(SysUser info)
{
using (var session = DBHelper.GetSession())
{
session.Insert(info);
}
}
批量添加
public void Insert(List<SysUser> list)
{
using (var session = DBHelper.GetSession())
{
session.Insert(list);
}
}
修改
public void Update(SysUser info)
{
using (var session = DBHelper.GetSession())
{
session.Update(info);
}
}
批量修改
public void Update(List<SysUser> list)
{
using (var session = DBHelper.GetSession())
{
session.Update(list);
}
}
洗掉
public void Delete(string id)
{
using (var session = DBHelper.GetSession())
{
session.DeleteById<SysUser>(id);
}
}
條件洗掉
using (var session = DBHelper.GetSession())
{
session.DeleteByCondition<SysUser>(string.Format("id>=12"));
}
查詢單個記錄
public SysUser Get(string id)
{
using (var session = DBHelper.GetSession())
{
return session.FindById<SysUser>(id);
}
}
using (var session = DBHelper.GetSession())
{
return session.FindBySql<SysUser>("select * from sys_user");
}
簡單查詢
using (var session = DBHelper.GetSession())
{
string sql = "select * from CARINFO_MERGE";
List<CarinfoMerge> result = session.FindListBySql<CarinfoMerge>(sql);
}
條件查詢
public List<BsOrder> GetList(int? status, string remark, DateTime? startTime, DateTime? endTime)
{
using (var session = DBHelper.GetSession())
{
SqlString sql = session.CreateSqlString(@"
select t.*, u.real_name as OrderUserRealName
from bs_order t
left join sys_user u on t.order_userid=u.id
where 1=1");
sql.AppendIf(status.HasValue, " and t.status=@status", status);
sql.AppendIf(!string.IsNullOrWhiteSpace(remark), " and t.remark like concat('%',@remark,'%')", remark);
sql.AppendIf(startTime.HasValue, " and t.order_time>=STR_TO_DATE(@startTime, '%Y-%m-%d %H:%i:%s') ", startTime.Value.ToString("yyyy-MM-dd HH:mm:ss"));
sql.AppendIf(endTime.HasValue, " and t.order_time<=STR_TO_DATE(@endTime, '%Y-%m-%d %H:%i:%s') ", endTime.Value.ToString("yyyy-MM-dd HH:mm:ss"));
sql.Append(" order by t.order_time desc, t.id asc ");
List<BsOrder> list = session.FindListBySql<BsOrder>(sql.SQL, sql.Params);
return list;
}
}
分頁查詢
public List<BsOrder> GetListPage(ref PageModel pageModel, int? status, string remark, DateTime? startTime, DateTime? endTime)
{
using (var session = DBHelper.GetSession())
{
SqlString sql = session.CreateSqlString(@"
select t.*, u.real_name as OrderUserRealName
from bs_order t
left join sys_user u on t.order_userid=u.id
where 1=1");
sql.AppendIf(status.HasValue, " and t.status=@status", status);
sql.AppendIf(!string.IsNullOrWhiteSpace(remark), " and t.remark like concat('%',@remark,'%')", remark);
sql.AppendIf(startTime.HasValue, " and t.order_time>=STR_TO_DATE(@startTime, '%Y-%m-%d %H:%i:%s') ", startTime.Value.ToString("yyyy-MM-dd HH:mm:ss"));
sql.AppendIf(endTime.HasValue, " and t.order_time<=STR_TO_DATE(@endTime, '%Y-%m-%d %H:%i:%s') ", endTime.Value.ToString("yyyy-MM-dd HH:mm:ss"));
string orderby = " order by t.order_time desc, t.id asc ";
pageModel = session.FindPageBySql<BsOrder>(sql.SQL, orderby, pageModel.PageSize, pageModel.CurrentPage, sql.Params);
return pageModel.GetResult<BsOrder>();
}
}
事務
public string Insert(BsOrder order, List<BsOrderDetail> detailList)
{
using (var session = DBHelper.GetSession())
{
try
{
session.BeginTransaction();
order.Id = Guid.NewGuid().ToString("N");
order.CreateTime = DateTime.Now;
decimal amount = 0;
foreach (BsOrderDetail detail in detailList)
{
detail.Id = Guid.NewGuid().ToString("N");
detail.OrderId = order.Id;
detail.CreateTime = DateTime.Now;
amount += detail.Price * detail.Quantity;
session.Insert(detail);
}
order.Amount = amount;
session.Insert(order);
session.CommitTransaction();
return order.Id;
}
catch (Exception ex)
{
session.RollbackTransaction();
Console.WriteLine(ex.Message + "\r\n" + ex.StackTrace);
throw ex;
}
}
}
異步查詢
public async Task<List<BsOrder>> GetListPageAsync(PageModel pageModel, int? status, string remark, DateTime? startTime, DateTime? endTime)
{
using (var session = await DBHelper.GetSessionAsync())
{
SqlString sql = session.CreateSqlString(@"
select t.*, u.real_name as OrderUserRealName
from bs_order t
left join sys_user u on t.order_userid=u.id
where 1=1");
sql.AppendIf(status.HasValue, " and t.status=@status", status);
sql.AppendIf(!string.IsNullOrWhiteSpace(remark), " and t.remark like concat('%',@remark,'%')", remark);
sql.AppendIf(startTime.HasValue, " and t.order_time>=STR_TO_DATE(@startTime, '%Y-%m-%d %H:%i:%s') ", startTime.Value.ToString("yyyy-MM-dd HH:mm:ss"));
sql.AppendIf(endTime.HasValue, " and t.order_time<=STR_TO_DATE(@endTime, '%Y-%m-%d %H:%i:%s') ", endTime.Value.ToString("yyyy-MM-dd HH:mm:ss"));
string orderby = " order by t.order_time desc, t.id asc ";
pageModel = await session.FindPageBySqlAsync<BsOrder>(sql.SQL, orderby, pageModel.PageSize, pageModel.CurrentPage, sql.Params);
return pageModel.GetResult<BsOrder>();
}
}
條件查詢(使用 ForContains、ForStartsWith、ForEndsWith、ForDateTime、ForList 等輔助方法)
public List<BsOrder> GetListExt(int? status, string remark, DateTime? startTime, DateTime? endTime, string ids)
{
using (var session = DBHelper.GetSession())
{
SqlString sql = session.CreateSqlString(@"
select t.*, u.real_name as OrderUserRealName
from bs_order t
left join sys_user u on t.order_userid=u.id
where 1=1");
sql.AppendIf(status.HasValue, " and t.status=@status", status);
sql.AppendIf(!string.IsNullOrWhiteSpace(remark), " and t.remark like @remark", sql.ForContains(remark));
sql.AppendIf(startTime.HasValue, " and t.order_time >= @startTime ", sql.ForDateTime(startTime.Value));
sql.AppendIf(endTime.HasValue, " and t.order_time <= @endTime ", sql.ForDateTime(endTime.Value));
sql.Append(" and t.id in @ids ", sql.ForList(ids.Split(',').ToList()));
sql.Append(" order by t.order_time desc, t.id asc ");
List<BsOrder> list = session.FindListBySql<BsOrder>(sql.SQL, sql.Params);
return list;
}
}
使用Lambda運算式單表查詢
單表分頁查詢使用ToPageList替換ToList即可
public void TestQueryByLambda6()
{
using (var session = DBHelper.GetSession())
{
SqlString<BsOrder> sql = session.CreateSqlString<BsOrder>();
string remark = "測驗";
List<BsOrder> list = sql.Query()
.WhereIf(!string.IsNullOrWhiteSpace(remark),
t => t.Remark.Contains(remark)
&& t.CreateTime < DateTime.Now
&& t.CreateUserid == "10")
.OrderByDescending(t => t.OrderTime).OrderBy(t => t.Id)
.ToList();
foreach (BsOrder item in list)
{
Console.WriteLine(ModelToStringUtil.ToString(item));
}
}
}
使用Lambda運算式聯表分頁查詢(簡單的聯表查詢,復雜情況請使用原生SQL或原生SQL和Lambda運算式混寫)
public void TestQueryByLambda7()
{
using (var session = DBHelper.GetSession())
{
SqlString<BsOrder> sql = session.CreateSqlString<BsOrder>();
int total;
List<string> idsNotIn = new List<string>() { "100007", "100008", "100009" };
List<BsOrder> list = sql.Query()
.Select<SysUser>(u => u.UserName, t => t.OrderUserName)
.Select<SysUser>(u => u.RealName, t => t.OrderUserRealName)
.LeftJoin<SysUser>((t, u) => t.OrderUserid == u.Id)
.LeftJoin<BsOrderDetail>((t, d) => t.Id == d.OrderId)
.Where<SysUser, BsOrderDetail>((t, u, d) => t.Remark.Contains("訂單") && u.CreateUserid == "1" && d.GoodsName != null)
.WhereIf<BsOrder>(true, t => t.Remark.Contains("測驗"))
.WhereIf<BsOrder>(true, t => !idsNotIn.Contains(t.Id))
.WhereIf<SysUser>(true, u => u.CreateUserid == "1")
.OrderByDescending(t => t.OrderTime).OrderBy(t => t.Id)
.ToPageList(1, 20, out total);
foreach (BsOrder item in list)
{
Console.WriteLine(ModelToStringUtil.ToString(item));
}
}
}
原生SQL和Lambda運算式混寫
public void TestQueryByLambda9()
{
using (var session = DBHelper.GetSession())
{
SqlString<BsOrder> sql = session.CreateSqlString<BsOrder>(@"
select t.*, u.real_name as OrderUserRealName
from bs_order t
left join sys_user u on t.order_userid=u.id
where 1=1");
List<BsOrder> list = sql.Where(t => t.Status == int.Parse("0")
&& t.Status == new BsOrder().Status
&& t.Remark.Contains("訂單")
&& t.Remark != null
&& t.OrderTime >= new DateTime(2010, 1, 1)
&& t.OrderTime <= DateTime.Now.AddDays(1))
.WhereIf<SysUser>(true, u => u.CreateTime < DateTime.Now)
.OrderByDescending(t => t.OrderTime).OrderBy(t => t.Id)
.ToList();
foreach (BsOrder item in list)
{
Console.WriteLine(ModelToStringUtil.ToString(item));
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/418028.html
標籤:.NET技术
