一、常見開源ORM框架
比喻:Kerosene ORM,DbLinq,Dapper,DynamicQuery,elinq,glinq,NPoco,Relinq,EF,ServiceStack.OrmLite,IQToolkit,對於這些框架,在單表查詢這塊支持的還蠻可以,但是對於多表查詢的那種語法,我真有點接受不了,總感覺怪怪的,直觀感覺就是沒有了linq語法的那種美感,請忽視我的挑剔與自不量力,純屬個人喜好。
例如:
var cmd = link
.From( x => x.Employees.As( x.Emp ) ) .Join( x => x.Countries.As( x.Ctry ).On( x.Emp.CountryId == x.Ctry.Id ) ) .Select( x => x.Emp.Id, x => x.Emp.FirstName, x => x.LastName ) .Select( x => x.Ctry.Id, x => x.Ctry.Name ) .OrderBy( x => x.Emp.Id );
List<School> dataList = db.Sqlable()
.Form("school", "s") .Join("student", "st", "st.id", "s.id", JoinType.INNER) .Join("student", "st2", "st2.id", "st.id", JoinType.LEFT).Where("s.id>100 and s.id<@id").SelectToList<School>("st.*", new { id = 1 });
var joinQuery = new JoinSqlBuilder<User, User> ().
LeftJoin<User, Address> (x => x.Id, x => x.UserId).ToSql ();
var testQuery = from c in db.Customers
from o in c.Orders from d in o.Details where o != exclude select d; var test = testQuery.ToList();
var query = from c in db.Customers
where c.CustomerID == "ALFKI" join o in db.Orders on new {a = c.CustomerID, b = c.CustomerID} equals new {a = o.CustomerID, b = o.CustomerID} select new {c, o};
等等。其次就是代碼量相當龐大,閱讀起來費力,雖然都是從接口、抽象類開始閱讀,而且調試起來去理解它的代碼需要耗費大量時間,且相關文檔有些不完整。再次陷入了困境,前前后后也花了一些時間,於是靜下心來想想,為何我不重新梳理下自己的計划了,原本是想在前人的基礎上去修改修改就變成自己的了,但是核心代碼還是別人的,自己沒有掌握關鍵技術。看來這條路走不通了,只能靠自己了。
二、ORM所需具備的條件
在日常開發中,如果是做業務邏輯開發一定會離不開單表增刪改查、多表關聯查詢、存儲過程、分頁、聚合函數使用等。這里插播一段,因為我主要做后端開發以及框架搭建,平日最討厭某某說,后台不就是增刪改查嗎?只要一聽到類似的話語,我心中立即會有10萬頭草泥馬向他奔去,鄙夷感頓生。但是馬上會說,你怎么知道就只有增刪改查了?哈哈。有點扯遠了。不管是業務邏輯離不開這些,就一些框架組件也會將一些數據持久化,它們也離不開與數據庫打交道。那么我覺得這個ORM必須具備如下條件:
A、支持CRUD標准接口;
B、支持多表聯合查詢接口,並且使用linq語法,但是一定不使用linq的那個join方式;
C、支持聚合函數、支持分組以及hanving、支持存儲過程調用、支持分頁,支持sql語句,支持事務;
D、支持部分常用C# 函數調用;
E、支持與元數據進行映射的工具;
F、能擴展oracle,mysql等主流數據庫;
如果能滿足上述6個大條件,那么這個輪子基本上就滿足日常開發中80%左右的場景了,那么快速開發也就不在話下了。
三、適合我的ORM操作示例
有了上面的基礎,結合一下目前主流的ORM框架,那么就可以想象下ORM的部分使用示例了。
A、單表增刪改查
Insert:
Db<T>.Insert(實體對象);
Delete:
Db<T>.Delete(w => w.條件字段== 4);
Update:
Db<T>.Update(up => new 實體對象{需要修改字段= "xxxxxx" }, wh => wh.條件字段== 4);
Select:
Db<T>.Single(w => w.條件字段.Contains("@")); //單條記錄
Db<T>.Select(w => w.條件字段.Contains("@")); //多條記錄
B、多表聯合查詢
join:
var results = (from u in Db<T>.查詢對象a join ur in Db<T>.查詢對象b on new { u = u.條件字段1, a = u.條件字段2 } equals new { u = ur.條件字段1, a = ur.條件字段2 } join r in Db<T>.查詢對象c on ur.條件字段3 equals r.條件字段3 where u.條件字段4 == 1 orderby u.條件字段5 select new object //可以匿名 select new { v= u.字段, vv= u.字段, vvv= u.字段, vvvv= r.字段 }).設置表關聯類型(類型Inner, 類型.left);
分頁:
results.Page(1,1);
C、存儲過程
var dbParameters = new DbParameterCollection { new DbParameter{DbType = DbType.Int32,Name = 輸入參數名稱,Value = 1,Direction = ParameterDirection.Input}, new DbParameter{DbType = DbType.Int32,Name = 輸出參數名稱,Direction = ParameterDirection.Output } }; var affectCount = Db.執行存儲過程(存儲過程名稱, 存儲過程參數); //這里是返回影響行數,還可以擴展返回ilist<T>集合,dataset對象 var returnc = dbParameters[output參數名稱].Value;
D、執行sql語句
var ds = Db.執行查詢("select * from demoTable"); //還可以擴展返回ilist<T>集合,影響行數等
foreach (DataRow row in ds.Tables[0].Rows) { Console.WriteLine(row[0]); }
E、事務
using (var 數據庫對象提供者實例= Db.默認實例) { try { Begin(); //開始事務 //to do... Commit(); //提交事務 } catch (Exception) { Rollback(); //回滾事務 } }
F、多表聯合查詢分組
var resultList = (from a in Db<T>.查詢對象1 join b in Db<T>.查詢對象1 on a.條件字段1 equals b.條件字段2 group new {對象a, 對象b} by new {對象a.字段} into g where g.Sum(m=>m.對象b.字段)>200 select new { userId= g.Key.對象a.字段,
TotalScore = g.Max(b => b.對象b.字段) }).ToList();
G、其他就不一一列舉了,具體詳見后續博文。
