開源一個基於dotnet standard的輕量級的ORM框架-Light.Data

aquilahkj發表於2019-05-22

   還在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或以上

 

 

連線配置

{
  "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 }

 

基本操作

  • 基本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                   .GroupBy (x => new LevelIdAgg () {
 5                       LevelId = x.LevelId,
 6                       Data = Function.Count ()
 7                    })
 8                   .ToList ();
 9 
10 // 日期格式化統計
11 var list = context.Query<TeUser> ()
12                   .GroupBy (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

相關文章