LambdaToSql(輕量級ORM) 入門篇 開源專案

lightwing發表於2021-09-09

為什麼開發(背景)

  1. 最開始使用的是 sqlDbHelper,有微軟的,有自己寫的。

  2. 後來開始使用比較成熟的框架開發,使用過一段時間的Hibernate,後期主要使用 Entity FrameWork。

  3. 發現表越多 業務越複雜後,越不好控制專案,所以慢慢的自己根據業務寫了一個小工具,也就是本文說的 LambdaToSql。

  4. 最開始的功能 主要是準備替代DbHelper的,慢慢的把對映關係加上了,再後來重構了幾次,就慢慢的代替了EF的功能。

  5. 現在有幾個成熟的專案在使用,軟體也會一直維護下去,現在基本都是核心功能,暫時沒往大而全去做。

ORM介紹

  1. 鏈式查詢、鏈式更新、鏈式刪除、鏈式插入、複雜模型的查詢、ADO.NET。

  2. 支援資料庫:現在只支援 MS Sql Server,其他資料庫暫時未做支援處理,裡面預留了對其它資料庫支援的介面,但未實現程式碼邏輯。

  3. 資料庫預留介面:Oracle、Mysql、Access。

  4. 功能: 基本CURD(新增,修改,讀取,刪除)功能,批次修改,DbFirst,表快取。

  5. 全部使用Lambda語法,開發簡潔,程式碼乾淨,後期好維護。

  6. 有點2:效能高,基本接近於原生ADO,語法簡單,功能強大,持續更新維護。

  7. 其實LambdaToSql不能算是一個ORM,主要功能其實還應該算是Dapper替代產品,主要是把對映物件透過Lambda形式轉換成sql語句,透過Ado做 CURD操作。

  8. 缺點1:不支援多表查詢,Join效能還是比較低,但後期還是會支援join查詢。

  9. 缺點2:暫時不支援外部自定義函式和繼承覆蓋重寫,後期慢慢也會開放出來。

  10. 如果有想自定義的,可以直接使用原始碼改動哦。

 

效能測試

  1. 測試環境:   硬碟:三星 SSD 850 EVO;     CPU:i7-7700K

  2. 新增100w條資料 耗時大概250s內

  3. 查詢100w條資料並生成實體.Tolist(),大概3s

  4. 100w資料,每頁50條,取中間資料,大概100ms內

  5. 插入/更新/查詢 單條資料 大概20ms內

  6. 刪除 單條大概 20ms內

 

開源地址

  1. 碼雲gitee: 

  2. Demo示例:

 

如何安裝

  1. 原始碼方式:可以直接在gitee下載,在專案中直接使用

  2. 透過Nuget下載引用: 開啟Nuget  搜尋:LambdaToSql 就可以了

  3. Nuget命令方式:  Install-Package LambdaToSql

 

Config配置,連結資料庫 

  
    
  

 

初始化LambdaToSql 物件

//預設方式LambdaToSql.SqlClient DB = new LambdaToSql.SqlClient();
//自定義連結字串名稱var DB = new LambdaToSql.SqlClient(new LambdaToSql.EntityModel.DbContext()
            {
               ConnectionStringName = "ConnectionString1",
               SqlType = LambdaToSql.EntityModel.SqlType.MsSqlServer
            });

  

初次使用,如何生成實體類:DbFirst

圖片描述

//生成實體儲存路徑var saveFolder = "d:\class\";//生成全部實體DB.DbFirst.Create(saveFolder);//生成指定表實體物件DB.DbFirst.CreateByTable(saveFolder, new List() { "Table_ID", "Table_Guid" });

圖片描述

 

查詢

圖片描述

/// /// 查詢/// public void Query()
{    //查詢全部
    var list = DB.QueryTable().ToList();    //Find主鍵查詢,支援Guid 和int 自增主鍵
    var entity = DB.QueryTable().Find(200);    //In查詢
    var arr = new int?[] { 100, 101, 102, 103 }.ToList();    var list1 = DB.QueryTable(ex => arr.Contains(ex.ID)).ToList();    //Not In 查詢 
    var list2 = DB.QueryTable(ex => ex.ID.ExNotIn(arr)).ToList();//有問題
    var list2_1 = DB.QueryTable(ex => arr.NotContains(ex.ID)).ToList();//有問題    // Like  查詢
    var list3 = DB.QueryTable().Where(ex => ex.LoginName.Contains("15")).ToList();//(LoginName like '%15%')
    var list4 = DB.QueryTable().Where(ex => ex.LoginName.NotContains("15")).ToList();//(LoginName not like '%15%') //有問題
    var list5 = DB.QueryTable().Where(ex => ex.LoginName.StartsWith("15")).ToList();//(LoginName like '15%')
    var list6 = DB.QueryTable().Where(ex => ex.LoginName.EndsWith("15")).ToList();//(LoginName like '%15')    //排序
    var list7 = DB.QueryTable().OrderBy(ex => ex.CreateTime).OrderByDescending(ex => ex.LoginName).ToList();    //分組
    var list8 = DB.QueryTable().GroupBy(ex => new { ex.LoginName, ex.UserName }).ToList();    //只取特定欄位
    var list9 = DB.QueryTable().Select(ex => new { ex.LoginName, ex.UserName }).ToList();    //top N
    var list10 = DB.QueryTable().Take(10).ToList();    //第幾頁
    var list11 = DB.QueryTable().Skip(2).Take(10).ToList();    //取第一條資料
    var list12 = DB.QueryTable().First();    var list13 = DB.QueryTable().FirstOrDefault();    //分頁  2005,2008使用row_number分頁,2012以上使用offset分頁形式
    int total = 0;    var list14 = DB.QueryTable().Skip(15).Take(30).ToPageList(ref total);    //分組 select 比原始去重效能要高一些
    DB.QueryTable().GroupBy(ex => new { ex.UserName, ex.LoginName })
                                            .Select(ex => new { ex.UserName, ex.LoginName })
                                            .ToList();    //判斷滿足條件的資料是否存在
    var flag = DB.QueryTable().Any();    //判斷滿足條件的資料是否存在
    var flag1 = DB.QueryTable(ex => ex.ID == 2000).Any();
}

圖片描述

 

函式處理

圖片描述

/// /// 函式處理/// private void Fun()
{    //求和
    var num1 = DB.QueryTable().Sum(ex => ex.IsDelete);    //最小值
    var num2 = DB.QueryTable().Min(ex => ex.IsDelete);    //最大值
    var num3 = DB.QueryTable().Max(ex => ex.IsDelete);    //平均值
    var num4 = DB.QueryTable().Avg(ex => ex.IsDelete);    //總數
    var num5 = DB.QueryTable().Count();
}

圖片描述

 

新增

圖片描述

/// /// 新增資料/// public void Inser()
{    //新增單個實體物件
    var entity = new EntityModel.Table_ID()
    {
        LoginName = "登入使用者:",
        UserName = "使用者名稱:",
        PassWord = "密碼-",
        Gender = "男",
        IsDelete = 0,
        Mobile = "15804066511",
        Remark = "備註",
        Address = "地址:",
        CreateTime = DateTime.Now
    };    var ret = DB.InsertTble(entity).ExecuteNonQuery();//返回主鍵值    //只新增某幾列
    var i = DB.InsertTble(entity).InsertColumns(ex => new { ex.LoginName, ex.UserName, ex.Remark }).ExecuteNonQuery();    //忽略某些列
    var i1 = DB.InsertTble(entity).IgnoreColumns(ex => new { ex.Mobile, ex.PassWord }).ExecuteNonQuery();
}

圖片描述

 

修改

  1. NULL列不做更新處理

  2. 暫時只支援uniqueidentifier和int自增型別單主鍵

圖片描述

/// /// 更新資料/// public void Update()
{    //更新單個實體物件
    var entity = DB.QueryTable(ex => ex.ID == 200).FirstOrDefault();
    entity.PassWord = "12345";
    entity.LoginName = "LambdaToSql";
    entity.UserName = "LambdaToSql1";    var i = DB.UpdateTble(entity).ExecuteNonQuery();    //更新特定欄位,不指定不更新
    var i1 = DB.UpdateTble(entity).UpdateColumns(ex => new { ex.PassWord }).ExecuteNonQuery();    //忽略特定欄位,其他欄位都更新
    var i2 = DB.UpdateTble(entity).IgnoreColumns(ex => new { ex.UserName, ex.PassWord }).ExecuteNonQuery();    //條件更新 不需要取出實體物件 直接資料庫更新             
    var i3 = DB.UpdateTble(new EntityModel.Table_ID() { PassWord = "123456", LoginName = "12" }).Where(ex => ex.ID == 101).ExecuteNonQuery(true);
}

圖片描述

 

刪除

圖片描述

/// /// 刪除/// public void Delete()
{    //刪除單個實體,透過主鍵刪除 
    var entity = DB.QueryTable(ex => ex.ID == 200).FirstOrDefault();    var i = DB.DeleteTble(entity).ExecuteNonQuery();    //條件刪除 支援查詢裡面的所有條件寫法
    var i1 = DB.DeleteTble(ex => ex.ID == 201).ExecuteNonQuery();
}

圖片描述

 

事務

事務使用注意:

  1. 事務只能在同一個SqlClient物件有效;事務只能在同一個SqlClient物件有效;事務只能在同一個SqlClient物件有效;重要的事說三遍

  2. 跨SqlClient物件請用分散式事務(暫時內建不支援,後續版本會支援分散式事務) 

圖片描述

/// /// 事務/// public void Tran()
{    var sqlClient = new LambdaToSql.SqlClient();    try
    {
        sqlClient.BeginTran();//開啟事務        //新增單個實體物件
        var entity = new EntityModel.Table_ID()
        {
            LoginName = "登入使用者:",
            UserName = "使用者名稱:",
            PassWord = "密碼-",
            IsDelete = 0,
            CreateTime = DateTime.Now
        };        var entity1 = new EntityModel.Table_ID()
        {
            LoginName = "登入使用者:",
            UserName = "在破敗中崛起,在寂滅中復甦。滄海成塵,雷電枯竭,那一縷幽霧又一次臨近大地,世間的枷鎖被開啟了,一個全新的世界就此揭開神秘的一角:",
            PassWord = "密碼-",
            IsDelete = 0,
            CreateTime = DateTime.Now
        };        var entity2 = new EntityModel.Table_ID()
        {
            LoginName = "登入使用者:",
            UserName = "使用者名稱:",
            PassWord = "密碼-",
            IsDelete = 0,
            CreateTime = DateTime.Now
        };


        sqlClient.InsertTble(entity).ExecuteNonQuery();
        sqlClient.InsertTble(entity1).ExecuteNonQuery();//錯誤 UserName太長=>回滾        sqlClient.InsertTble(entity2).ExecuteNonQuery();

        sqlClient.CommitTran();//提交事務    }    catch (Exception ex)
    {
        sqlClient.RollbackTran();//回滾事務    }
}

圖片描述

 

ADO

圖片描述

/// /// Ado/// public void Ado()
{    var sql = "select top(10) * from table_id";    var sdr = DB.Ado.ExecuteReader(sql);    var list = new List();    while (sdr.Read())
    {
        list.Add(sdr[0].ToString());
    }
    sdr.Close();    var Dt = DB.Ado.ExecuteTable(sql);    var ls1 = DB.Ado.ExecuteScalar(sql);    var ls = DB.Ado.ExecuteScalars(sql);    var i = DB.Ado.ExecuteNonQuery("update top (10) table_id set imgurl = 'img1'");
}

圖片描述

 

後續計劃

  1. 繼續維護程式碼和升級新功能

  2. 把類庫UML圖釋出出來

  3. 把類介面和實現文件 整理好 釋出出來

  4. 會在開源一個關於WebApi的整體框架結構

  5. 最近另一個開源專案:   這是個通用類庫專案,把平時常用的整理了下,自己也一直在使用此類庫

 

結尾

  1. 希望大家多多提bug

  2. 希望大家多多提意見

  3. 最後,感謝SqlSugar專案作者開源

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/3407/viewspace-2804520/,如需轉載,請註明出處,否則將追究法律責任。

相關文章