[開源]無sql之旅-Chloe.ORM之增刪查改


扯淡

這是一款輕量、高效的.NET C#數據庫訪問框架(ORM)。查詢接口借鑒 Linq(但不支持 Linq)。借助 lambda 表達式,可以完全用面向對象的方式就能輕松執行多表連接查詢、分組查詢、聚合函數查詢、插入數據、刪除和更新滿足條件的數據等操作。

上篇文章中, Chloe.ORM 初次對外拋頭露面,雖然是在重復造輪子,但還是得到部分園友的支持與認可,LZ非常感謝!上文主要展示 Chloe 的查詢方式以及支持的 lambda 寫法,本文主題是多表連接查詢、插入數據、更新數據、刪除數據以及事務支持。

導航

Chloe.ORM

事前准備

實體:

public enum Gender
{
    Man = 1,
    Woman
}

[Table("Users")]
public class User
{
    [Column(IsPrimaryKey = true)]
    [AutoIncrement]
    public int Id { get; set; }
    public string Name { get; set; }
    public Gender? Gender { get; set; }
    public int? Age { get; set; }
    public int? CityId { get; set; }
    public DateTime? OpTime { get; set; }
}

首先,創建一個 DbContext:

IDbContext context = new MsSqlContext(DbHelper.ConnectionString);

再創建一個 IQuery<T>:

IQuery<User> q = context.Query<User>();

多表連接查詢

在上篇文章中,介紹了 Chloe 的查詢功能。Chloe 執行連接查詢時,建立連接(IQuery<T>接口調用 InnerJoin、LeftJoin、RightJoin 和 FullJoin)返回的是 IJoiningQuery 的泛型對象,如果看過框架源碼的同學可能會知道,IJoiningQuery 的泛型參數最多有5個,而且有5個泛型參數的那個類(IJoiningQuery<T1,T2,T3,T4,T5>)就只有一個 Select 方法,也就是說不能繼續連接其它表,最多有5個表建立連接,真的是這樣嗎?如果你這樣認為你就錯了!我們來看看怎么建立超過5個表的連接。

偽代碼:

//假設已經有5個表建立了連接的對象為 jq_q1_q5
IJoiningQuery<T1, T2, T3, T4, T5> jq_q1_q5 = null;

//jq_q1_q5 調用 Select 方法,返回一個包含 T1-T5 的 IQuery<T> 對象 view_q1_q5
var view_q1_q5 = jq_q1_q5.Select((t1, t2, t3, t4, t5) => new { T1 = t1, T2 = t2, T3 = t3, T4 = t4, T5 = t5 });

//假設第6個表的 IQuery<T6> 對象為 q6
IQuery<T6> q6 = null;

//這時,view_q1_q5 與 q6 建立連接,返回 IJoiningQuery 對象 jq
var jq = view_q1_q5.InnerJoin(q6, (t1_t5, t6) => t1_t5.T5.XX == t6.XXX);

//然后我們調用 jq 的 Select 方法,返回一個包含 T1-T6 的 IQuery<T> 對象 view。
//view 又是一個 IQuery<T> 對象,泛型參數為包含 T1-T6 所有信息的匿名對象(這時候還沒有發起 sql 查詢哦),拿到它,我們就可以為所欲為了。
var view = jq.Select((t1_t5, t6) => new { T1 = t1_t5.T1, T2 = t1_t5.T2, T3 = t1_t5.T3, T4 = t1_t5.T4, T5 = t1_t5.T5, T6 = t6 });

//可以直接查出數據庫中 T1-T6 的所有信息
view.ToList();

//也可以選取 T1-T6 中我們想要的字段
view.Select(a => new { a.T1.xx, a.T2.xx, a.T3.xx /*...*/}).ToList();

這樣,周而復始,就可以實現無限表連接了,相對沒有 Linq 那么直觀,但這是我能想到最好的方式了。如果哪位同學有更好的設計,望分享,不勝感激!

Chloe 的另外亮點是聚合函數查詢和分組查詢,這兩個查詢有別於 Linq,更趨於標准 sql 思想,配合連接查詢使用,可以應對一些稍微復雜的查詢,可以翻看上篇文章使用進階部分,有簡單介紹,連接地址:http://www.cnblogs.com/so9527/p/5636216.html#more_usage

目前市面上很多 ORM 都只是支持單表查詢,能靈活操作連接查詢和聚合函數查詢的,除 EF 和 linq to sql 外,為數不多,這也是我造輪子的原因之一。

插入數據

方式1

以 lambda 的形式插入:

IDbContext context = new MsSqlContext(DbHelper.ConnectionString);

//返回主鍵 Id
int id = (int)context.Insert<User>(() => new User() { Name = "lu", Age = 18, Gender = Gender.Man, CityId = 1, OpTime = DateTime.Now });
/*
 * INSERT INTO [Users]([Name],[Age],[Gender],[CityId],[OpTime]) VALUES(N'lu',18,1,1,GETDATE());SELECT @@IDENTITY
 */

方式2

IDbContext context = new MsSqlContext(DbHelper.ConnectionString);

User user = new User();
user.Name = "lu";
user.Age = 18;
user.Gender = Gender.Man;
user.CityId = 1;
user.OpTime = new DateTime(1992, 1, 16);

//會自動將自增 Id 設置到 user 的 Id 屬性上
user = context.Insert(user);
/*
 * String @P_0 = "lu";
   Gender @P_1 = Man;
   Int32 @P_2 = 18;
   Int32 @P_3 = 1;
   DateTime @P_4 = "1992/1/16 0:00:00";
   INSERT INTO [Users]([Name],[Gender],[Age],[CityId],[OpTime]) VALUES(@P_0,@P_1,@P_2,@P_3,@P_4);SELECT @@IDENTITY
 */

第一種方式比較接近 sql 的寫法,可以有選擇的插入。第二種方式則會將所有映射的字段都插入。對於插入數據需求,這兩種方式我想應該可以滿足了。

更新數據

方式1

以 lambda 的形式更新:

MsSqlContext context = new MsSqlContext(DbHelper.ConnectionString);

context.Update<User>(a => new User() { Name = a.Name, Age = a.Age + 100, Gender = Gender.Man, OpTime = DateTime.Now }, a => a.Id == 1);
/*
 * UPDATE [Users] SET [Name]=[Users].[Name],[Age]=([Users].[Age] + 100),[Gender]=1,[OpTime]=GETDATE() WHERE [Users].[Id] = 1
 */

//批量更新
//給所有女性朋友年輕 10 歲
context.Update<User>(a => new User() { Age = a.Age - 10, OpTime = DateTime.Now }, a => a.Gender == Gender.Woman);
/*
 * UPDATE [Users] SET [Age]=([Users].[Age] - 10),[OpTime]=GETDATE() WHERE [Users].[Gender] = 2
 */

方式2

MsSqlContext context = new MsSqlContext(DbHelper.ConnectionString);

User user = new User();
user.Id = 1;
user.Name = "lu";
user.Age = 28;
user.Gender = Gender.Man;
user.OpTime = DateTime.Now;

context.Update(user); //會更新所有映射的字段
/*
 * String @P_0 = "lu";
   Gender @P_1 = Man;
   Int32 @P_2 = 28;
   Nullable<Int32> @P_3 = NULL;
   DateTime @P_4 = "2016/7/8 11:28:27";
   Int32 @P_5 = 1;
   UPDATE [Users] SET [Name]=@P_0,[Gender]=@P_1,[Age]=@P_2,[CityId]=@P_3,[OpTime]=@P_4 WHERE [Users].[Id] = @P_5
 */

/*
 * 支持只更新屬性值已變的屬性
 */

context.TrackEntity(user);//在上下文中跟蹤實體
user.Name = user.Name + "1";
context.Update(user);//這時只會更新被修改的字段
/*
 * String @P_0 = "lu1";
   Int32 @P_1 = 1;
   UPDATE [Users] SET [Name]=@P_0 WHERE [Users].[Id] = @P_1
 */

像第一種方式可以批量更新數據方法,我覺得在實際開發中很有必要,且不可或缺。

之前,同事用 EF 開發一個功能,需要批量更新,他的做法是將所有滿足條件的數據給查出來,然后挨個賦值,最后統一 SaveChanges(),開發時由於數據量少,沒發現問題。部署上線了以后,用戶隨便點擊一下保存,這個方法執行都要好久,瞬間懵了,不多說為什么,你懂的!雖然有人基於 EF 做了一個支持批量更新的 EF 擴展類庫,經過各方面考慮,最終不敢輕易冒風險引入項目中。那就拼接一句批量 Update 的sql唄,原生態執行。Oh!想到拼 sql,心中一萬個草泥馬路過!!!都 .net4.5+ 時代,.net Core 都出了,還執着手寫sql?這費時費力的活咱90后程序員可不干!雖然我 sql 寫得很溜,但不到沒轍的時候我是不會去拼 sql。項目開發階段,我是秉着怎么快怎么做原則,有能10分鍾解決問題的方式,我是不會選擇10分鍾+1秒的其他方法!多一秒也不行!至於優化,那是后事。
自己動手,能根據需求定制理想的功能,這也是我造輪子的原因之一。

刪除數據

方式1

以 lambda 的形式刪除:

MsSqlContext context = new MsSqlContext(DbHelper.ConnectionString);

context.Delete<User>(a => a.Id == 1);
/*
 * DELETE [Users] WHERE [Users].[Id] = 1
 */

//批量刪除
//刪除所有不男不女的用戶
context.Delete<User>(a => a.Gender == null);
/*
 * DELETE [Users] WHERE [Users].[Gender] IS NULL
 */

方式2

MsSqlContext context = new MsSqlContext(DbHelper.ConnectionString);

User user = new User();
user.Id = 1;
context.Delete(user);
/*
 * Int32 @P_0 = 1;
   DELETE [Users] WHERE [Users].[Id] = @P_0
 */

刪除數據就這么簡單。

事務支持

Chloe 的事務操作方法在 DbContext.CurrentSession 屬性里:

MsSqlContext context = new MsSqlContext(DbHelper.ConnectionString);

IDbSession dbSession = context.CurrentSession;
try
{
    dbSession.BeginTransaction();

    //to do somethings here...

    dbSession.CommitTransaction();
}
catch
{
    dbSession.RollbackTransaction();
}

事務是每個 ORM 必備的功能。太簡單,本來不想寫進來的,想想,寫吧,湊個字數也好。

結語

Chloe.ORM 主打便捷、高效,無論是 IDbContext 還是 IQuery<T> 接口,設計極其簡單,基本一看就懂,一用就會。並且不依賴任何配置,上手簡單,傳個數據庫連接字符串就能跑,我就喜歡這樣傻瓜式開發。話說有一點我很納悶,C# 是一門高度簡化的語言,很多人說微軟把程序員培養得越來越傻,試問,傻瓜式開發不好嗎?這是開發語言的進步啊,我們為什么要拒絕!那些人是不是都喜歡折騰?說句不好聽的,如果一門語言真把一個程序員變“傻”,我想,那位程序員肯定不是好程序員!扯遠了,嘿嘿。

秉着開源共享精神,促進國內開源事業發展,Chloe.ORM 完全開源,遵循 Apache2.0 協議。

GitHub:https://github.com/shuxinqin/Chloe

開源中國:http://www.oschina.net/p/chloe-orm

ps:小弟不才,文化、技術功底有限,必有不足之處,望各路大神多多指點,非常感謝。也請有異議的同學,點反對的同時,麻煩也留個建議再離開,行嗎?謝謝。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM