LambdaToSql(輕量級ORM) 入門篇 開源項目

爲何開發(背景)

  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: https://gitee.com/wangshuyu/LambdaToSql
  2. Demo示例:https://gitee.com/wangshuyu/LambdaToSql_Demo

 

如何安裝

  1. 源碼方式:能夠直接在gitee下載源代碼,在項目中直接使用
  2. 經過Nuget下載引用: 打開Nuget  搜索:LambdaToSql 就能夠了
  3. Nuget命令方式:  Install-Package LambdaToSql

 

Config配置,連接數據庫 

  <connectionStrings>
    <add name="ConnectionString" connectionString="Server=.;Database=LambdaToSql;User ID=sa;Password=abc@123;" providerName="System.Data.SqlClient" />
  </connectionStrings>

 

初始化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<string>() { "Table_ID", "Table_Guid" });

 

查詢

/// <summary>
/// 查詢
/// </summary>
public void Query()
{
    //查詢所有
    var list = DB.QueryTable<EntityModel.Table_ID>().ToList();

    //Find主鍵查找,支持Guid 和int 自增主鍵
    var entity = DB.QueryTable<EntityModel.Table_ID>().Find(200);

    //In查詢
    var arr = new int?[] { 100, 101, 102, 103 }.ToList();
    var list1 = DB.QueryTable<EntityModel.Table_ID>(ex => arr.Contains(ex.ID)).ToList();

    //Not In 查詢 
    var list2 = DB.QueryTable<EntityModel.Table_ID>(ex => ex.ID.ExNotIn(arr)).ToList();//有問題
    var list2_1 = DB.QueryTable<EntityModel.Table_ID>(ex => arr.NotContains(ex.ID)).ToList();//有問題

    // Like  查詢
    var list3 = DB.QueryTable<EntityModel.Table_ID>().Where(ex => ex.LoginName.Contains("15")).ToList();//(LoginName like '%15%')
    var list4 = DB.QueryTable<EntityModel.Table_ID>().Where(ex => ex.LoginName.NotContains("15")).ToList();//(LoginName not like '%15%') //有問題
    var list5 = DB.QueryTable<EntityModel.Table_ID>().Where(ex => ex.LoginName.StartsWith("15")).ToList();//(LoginName like '15%')
    var list6 = DB.QueryTable<EntityModel.Table_ID>().Where(ex => ex.LoginName.EndsWith("15")).ToList();//(LoginName like '%15')

    //排序
    var list7 = DB.QueryTable<EntityModel.Table_ID>().OrderBy(ex => ex.CreateTime).OrderByDescending(ex => ex.LoginName).ToList();

    //分組
    var list8 = DB.QueryTable<EntityModel.Table_ID>().GroupBy(ex => new { ex.LoginName, ex.UserName }).ToList();

    //只取特定字段
    var list9 = DB.QueryTable<EntityModel.Table_ID>().Select(ex => new { ex.LoginName, ex.UserName }).ToList();

    //top N
    var list10 = DB.QueryTable<EntityModel.Table_ID>().Take(10).ToList();
    //第幾頁
    var list11 = DB.QueryTable<EntityModel.Table_ID>().Skip(2).Take(10).ToList();

    //取第一條數據
    var list12 = DB.QueryTable<EntityModel.Table_ID>().First();
    var list13 = DB.QueryTable<EntityModel.Table_ID>().FirstOrDefault();

    //分頁  2005,2008使用row_number分頁,2012以上使用offset分頁形式
    int total = 0;
    var list14 = DB.QueryTable<EntityModel.Table_ID>().Skip(15).Take(30).ToPageList(ref total);

    //分組 select 比原始去重性能要高一些
    DB.QueryTable<EntityModel.Table_ID>().GroupBy(ex => new { ex.UserName, ex.LoginName })
                                            .Select(ex => new { ex.UserName, ex.LoginName })
                                            .ToList();

    //判斷知足條件的數據是否存在
    var flag = DB.QueryTable<EntityModel.Table_ID>().Any();
    //判斷知足條件的數據是否存在
    var flag1 = DB.QueryTable<EntityModel.Table_ID>(ex => ex.ID == 2000).Any();
}

 

函數處理

/// <summary>
/// 函數處理
/// </summary>
private void Fun()
{
    //求和
    var num1 = DB.QueryTable<EntityModel.Table_ID>().Sum(ex => ex.IsDelete);

    //最小值
    var num2 = DB.QueryTable<EntityModel.Table_ID>().Min(ex => ex.IsDelete);

    //最大值
    var num3 = DB.QueryTable<EntityModel.Table_ID>().Max(ex => ex.IsDelete);

    //平均值
    var num4 = DB.QueryTable<EntityModel.Table_ID>().Avg(ex => ex.IsDelete);

    //總數
    var num5 = DB.QueryTable<EntityModel.Table_ID>().Count();
}

 

添加

/// <summary>
/// 添加數據
/// </summary>
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自增類型單主鍵
/// <summary>
/// 更新數據
/// </summary>
public void Update()
{
    //更新單個實體對象
    var entity = DB.QueryTable<EntityModel.Table_ID>(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);
}

 

刪除

/// <summary>
/// 刪除
/// </summary>
public void Delete()
{
    //刪除單個實體,經過主鍵刪除 
    var entity = DB.QueryTable<EntityModel.Table_ID>(ex => ex.ID == 200).FirstOrDefault();
    var i = DB.DeleteTble<EntityModel.Table_ID>(entity).ExecuteNonQuery();

    //條件刪除 支持查詢裏面的全部條件寫法
    var i1 = DB.DeleteTble<EntityModel.Table_ID>(ex => ex.ID == 201).ExecuteNonQuery();
}

 

事務

事務使用注意:

  1. 事務只能在同一個SqlClient對象有效;事務只能在同一個SqlClient對象有效;事務只能在同一個SqlClient對象有效;重要的事說三遍
  2. 跨SqlClient對象請用分佈式事務(暫時內置不支持,後續版本會支持分佈式事務) 
/// <summary>
/// 事務
/// </summary>
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

/// <summary>
/// Ado
/// </summary>
public void Ado()
{
    var sql = "select top(10) * from table_id";
    var sdr = DB.Ado.ExecuteReader(sql);
    var list = new List<string>();
    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. 最近另外一個開源項目: https://gitee.com/wangshuyu/CommonLib  這是個通用類庫項目,把平時經常使用的整理了下,本身也一直在使用此類庫

 

結尾

  1. 但願你們多多提bug
  2. 但願你們多多提意見
  3. 最後,感謝SqlSugar項目做者開源
相關文章
相關標籤/搜索