還在dotnet framework 2.0的時代,當時還沒有EF,而NHibernate之類的又太復雜,並且自己也有一些特殊需求,如查詢結果直接入表、水平分表和新增數據默認值等,就試着折騰個輕量點ORM框架,就慢慢有了這個Light.Data,也一直在公司和個人的項目使用,后來陸陸續續也支持了跨數據庫並在mono中使用。到了dotnet core來臨,也嘗試移植,1.0的時候由於類庫不完善,效果不理想。2.0的基本完善了,由於個人嚴重的強迫症和拖延症,一直在折騰細節、寫單元測試和磨文檔,磨到差不多3.0快來了。。。。
不說廢話了,Light.Data是一個輕量級的基於dotnet standard 2.0的ORM框架, 通過對實體模型類的Attribute或者配置文件進行配置與數據表的對應關系. 使用核心類DataContext對數據表進行CURD的操作.
PM> Install-Package Light.Data
支持數據庫
| 數據庫 | 說明 |
|---|---|
| SqlServer | 安裝Light.Data.Mssql類庫, 支持SqlServer 2008或以上 |
| Mysql | 安裝Light.Data.Mysql類庫, 支持Mysql 5.5或以上 |
| Postgre | 安裝Light.Data.Postgre類庫, 支持Postgre9.3或以上 |
-
使用文檔: https://aquilahkj.github.io/Light.Data.Site/#/zh-cn/
-
Github: https://github.com/aquilahkj/Light.Data2
連接配置
{ "lightData": { "connections": [ { "name": "mssql_db", "connectionString": "...", "providerName": "Light.Data.Mssql.MssqlProvider, Light.Data.Mssql" }, { "name": "mysq_db", "connectionString": "...", "providerName": "Light.Data.Mysql.MysqlProvider, Light.Data.Mysql" } ] } }
使用方式
// 直接使用 DataContext context = new DataContext("mssql"); // 創建子類 public class MyDataContext : DataContext { public MyDataContext() : base("mssql") { } } // 創建配置子類 public class MyDataContext : DataContext { public MyDataContext(DataContextOptions<MyDataContext> options) : base(options) { } } // 直接配置連接字符串和參數 (IServiceCollection) service.AddDataContext<MyDataContext>(builder => { builder.UseMssql(connectionString); builder.SetTimeout(2000); builder.SetVersion("11.0"); }, ServiceLifetime.Transient); // 默認配置文件配置 (IServiceCollection) service.AddDataContext<MyDataContext>(DataContextConfiguration.Global, config => { config.ConfigName = "mssql"; }, ServiceLifetime.Transient);
對象映射
1 [DataTable("Te_User", IsEntityTable = true)] 2 public class TeUser 3 { 4 /// <summary> 5 /// Id 6 /// </summary> 7 /// <value></value> 8 [DataField("Id", IsIdentity = true, IsPrimaryKey = true)] 9 public int Id 10 { 11 get; 12 set; 13 } 14 15 /// <summary> 16 /// Account 17 /// </summary> 18 /// <value></value> 19 [DataField("Account")] 20 public string Account 21 { 22 get; 23 set; 24 } 25 26 /// <summary> 27 /// Telephone 28 /// </summary> 29 /// <value></value> 30 [DataField("Telephone", IsNullable = true)] 31 public string Telephone 32 { 33 get; 34 set; 35 } 36 .... 37 }
子表對象關聯
1 [DataTable("Te_UserExtend", IsEntityTable = true)] 2 public class TeUserExtend 3 { 4 [DataField("Id", IsIdentity = true, IsPrimaryKey = true)] 5 public int Id 6 { 7 get; 8 set; 9 } 10 11 [DataField("MainId")] 12 public int MainId 13 { 14 get; 15 set; 16 } 17 18 [DataField("Data", IsNullable = true)] 19 public string Data 20 { 21 get; 22 set; 23 } 24 } 25 26 27 public class TeUserAndExtend : TeUser 28 { 29 [RelationField("Id", "MainId")] 30 public TeUserExtend Extend 31 { 32 get; 33 set; 34 } 35 }
基本操作
- 基本CURD
- 批量CUD
- 支持事務處理
- 支持數據字段默認值和自動時間戳
- 支持數據字段讀寫控制
- 查詢結果指定類或匿名類輸出
- 查詢直接插入數據表
1 var context = new DataContext(); 2 // 查詢單個數據 3 var item = context.Query<TeUser>().Where(x => x.Id == 10).First(); 4 // 查詢集合數據 5 var list = context.Query<TeUser>().Where(x => x.Id > 10).ToList(); 6 // 新增數據 7 var user = new TeUser() { 8 Account = "foo", 9 Password = "bar" 10 }; 11 context.Insert(user); 12 // 修改數據 13 user.Password = "bar1"; 14 context.Update(user); 15 // 刪除數據 16 context.Delete(user);
數據匯總
- 單列數據直接匯總
- 多列數據分組匯總
- 格式化分組字段
- 匯總數據直接插入數據表
1 // 普通匯總 2 var list = context.Query<TeUser> () 3 .Where (x => x.Id >= 5) 4 .Aggregate (x => new LevelIdAgg () { 5 LevelId = x.LevelId, 6 Data = Function.Count () 7 }) 8 .ToList (); 9 10 // 日期格式化統計 11 var list = context.Query<TeUser> () 12 .Aggtrgate (x => new RegDateFormatAgg () { 13 RegDateFormat = x.RegTime.ToString("yyyy-MM-dd"), 14 Data = Function.Count () 15 }) 16 .ToList ();
連表查詢
- 多表連接, 支持內連接, 左連接和右連接
- 支持查詢結果和匯總數據連接
- 連接查詢結果指定類或匿名類輸出
- 連接查詢結果直接插入數據表
1 // 內連接 2 var join = context.Query<TeUser> () 3 .Join<TeUserExtend>((x,y) => x.Id == y.Id); 4 5 // 統計結果連接實體表 6 var join = context.Query<TeMainTable>() 7 .GroupBy(x => new { 8 MId = x.MId, 9 Count = Function.Count(), 10 }) 11 .Join<TeSubTable>((x, y) => x.MId == y.Id);
執行SQL語句
- 直接使用SQL語句和存儲過程
- 支持對象參數
- 查詢結果指定類或匿名類輸出
- 存儲過程支持output參數
1 // 普通參數 2 var sql = "update Te_User set NickName=@P2 where Id=@P1"; 3 var ps = new DataParameter[2]; 4 ps[0] = new DataParameter("P1", 5); 5 ps[1] = new DataParameter("P2", "abc"); 6 var executor = context.CreateSqlStringExecutor(sql, ps); 7 var ret = executor.ExecuteNonQuery(); 8 9 // 對象參數 10 var sql = "update Te_User set NickName={nickname} where Id={id}"; 11 var executor = context.CreateSqlStringExecutor(sql, new { nickname = "abc", id = 5 }); 12 var ret = executor.ExecuteNonQuery();
單元測試
項目使用xUnit做單元測試,測試代碼地址:https://github.com/aquilahkj/Light.Data2/tree/master/test
每種數據庫均有300多組1000多用例的測試,覆蓋大部分代碼。
性能測試
目前只跟EF Core在同一電腦的Docker上的Sql Server 2017 for linux中做簡單的增刪改查性能對比測試,代碼地址 https://github.com/aquilahkj/OrmTest
1000次的增刪改和單條數據查詢
共5輪,每輪1000條的增刪改和1000條數據查詢
EF的測試結果

Light.Data測試結果

從對比看,查詢性能兩者差不多,新增性能Light.Data稍微占優,批量更新也稍微占優。
另外值得一提的是Postgre,批量增刪改性能比Sql Server快2,3倍,看來以后也要好好研究一下。

以上均是非嚴謹測試,僅供參考。
最后
本文只是簡單的介紹,具體使用方法可以查看文檔和參考測試用例,如有需要會寫具體使用的文章。
Light.Data這個項目這么多年來個人一直維護,也在不斷優化,不斷成長,但一直養在深閨,好不容易折騰開源也是希望能共享出去,給有需要的朋友多個選擇,同時也是給自己這么多年碼農的見證。
雖然現在ORM的框架非常非常多,也不是什么熱門新鮮事物,但總歸是個基礎的東西。
如果有朋友喜歡,不妨試試,可以的話,給個Star,十分歡迎意見或建議 :D
