前言
繼之前發的帖子【ORM-Dapper+DapperExtensions】,對Dapper的擴展代碼也進行了改進,同時加入Dapper 對Lambda表達式的支持。
由於之前缺乏對Lambda的知識,還是使用了拿來主義。研究了些案例,總歸有些問題:
1、只能生成sql、不能將值進行參數化。
2、lambda解析的代碼對sql語法的多樣式支持不夠
3、不開源,反編譯后發現可擴展性不強。
最后選擇了Dos.ORM(lambda支持的很好,開源的),在這里尊重原創,大家有興趣去支持下哈。
【作者博客:http://www.cnblogs.com/huxj/ 官方網站:http://ITdos.com/Dos/ORM/Index.html 】
開始研究Dos.ORM , 最后還是要是使用 Dapper 的, 同時還要基於 DapperExtensions的設計思想。
目的是把Dos.ORm的lambda解析核心代碼借鑒過來,然后用Dapper去執行。
想法不錯,但是實現起來廢了一番周折。
大概改動如下:
1、在DapperExtensions原有接口中擴展lambda方法
2、基於DapperExtensions的緩存機制 ,替換了Dos.ORM 對各個字段的和表結構的映射方式。
3、沿用DapperExtensions 中的定義方言接口進行生成sql的擴展
4、擴展了若干方法, 同時去除了Dos.ORM的一些特性.
這里必須要維護DapperExtensions 對實體類的0入侵的原則。
最后發現想讓ORM支持Lambda 的語法更多,最后還是要去擴展實體類。(各有利弊得失……)
語法
這里還是直接貼代碼了,為了照顧對dapper不熟悉的同學,下面將dapper、DapperExtensions、DapperExtensions+lambda 的語法分塊貼出來。
1、實體類
/// <summary> /// HY:實體對象 /// </summary> [Serializable] public class UsersEntity { /// <summary> /// 用戶ID /// </summary> public int UserId { get; set; } /// <summary> /// 登錄名稱 /// </summary> public string LoginName { get; set; } /// <summary> /// 密碼 /// </summary> public string Password { get; set; } /// <summary> /// 狀態 1:啟用 0禁用 /// </summary> public int? Status { get; set; } /// <summary> /// 創建時間 /// </summary> public DateTime? CreateTime { get; set; } /// <summary> /// 更新時間 /// </summary> public DateTime? UpdateTime { get; set; } /// <summary> /// 備注 /// </summary> public string Remark { get; set; } } /// <summary> /// Users:實體對象映射關系 /// </summary> [Serializable] public class UsersEntityORMMapper : ClassMapper<UsersEntity> { public UsersEntityORMMapper() { base.Table("Users"); //Map(f => f.UserInfo).Ignore();//設置忽略 //Map(f => f.Name).Key(KeyType.Identity);//設置主鍵 (如果主鍵名稱不包含字母“ID”,請設置) AutoMap(); } }
2、原生態的Dapper
//做為Demo以下語法的支持, 聲明的一個變量 IDbConnection connDemo = this.DBSession.Connection; IEnumerable<UsersEntity> listDemo = connDemo.Query<UsersEntity>("SELECT * FROM Users AS u "); IEnumerable<UsersEntity> listDemo1 = connDemo.Query<UsersEntity>("SELECT * FROM Users AS u WHERE u.UserId=@UserId AND u.LoginName LIKE @LoginName", new { UserId = 11, LoginName = "%王老五%" }); IEnumerable<UsersEntity> listDemo2 = connDemo.Query<UsersEntity>("SELECT * FROM Users AS u WHERE u.UserId IN @UserIds ", new { UserIds = new int[] { 1, 2, 3 }.AsEnumerable() }); string sqlDemo = @"SELECT * FROM Users AS u LEFT JOIN UserInfo AS ui ON u.UserId = ui.UserId"; IEnumerable<UsersModel> listDemo3 = connDemo.Query<UsersModel, UserInfoEntity, UsersModel>(sqlDemo, (user, userinfo) => { user.UserInfo = userinfo; return user; }).ToList(); string sqlDemo1 = @"SELECT * FROM Users AS u WHERE u.UserId=@UserId SELECT * FROM UserInfo AS ui WHERE ui.UserId=@UserId"; using (var multi = connDemo.QueryMultiple(sqlDemo1, new { UserId = 1 })) { var user = multi.Read<UsersEntity>().Single(); var userinfo = multi.Read<UserInfoEntity>().Single(); } connDemo.Execute("sql 語句"); //存儲過程 var UsersEntity = connDemo.Query<UsersEntity>("spGetUser", new { Id = 1 }, commandType: CommandType.StoredProcedure).SingleOrDefault();
2、DapperExtensions
//實體類 UsersEntity entity = new UsersEntity(); int userId = this.Insert(entity);//插入 bool isSuccess = this.Update(entity);//更新 int count = this.Delete(entity);//刪除 entity = this.GetById(1);//獲得實體 int count1 = this.Count(new { ID = 1 }); //數量 //查詢所有 IEnumerable<UsersEntity> list = this.GetAll(); //條件查詢 IList<ISort> sort = new List<ISort>(); sort.Add(new Sort { PropertyName = "UserId", Ascending = false }); IEnumerable<UsersEntity> list1 = this.GetList(new { UserId = 1, Name = "123" }, sort); //orm 拼接條件 查詢 繁瑣 不靈活 不太好用 IList<IPredicate> predList = new List<IPredicate>(); predList.Add(Predicates.Field<UsersEntity>(p => p.LoginName, Operator.Like, "不知道%")); predList.Add(Predicates.Field<UsersEntity>(p => p.UserId, Operator.Eq, 1)); IPredicateGroup predGroup = Predicates.Group(GroupOperator.And, predList.ToArray()); list = this.GetList(predGroup); //分頁查詢 long allRowsCount = 0; this.GetPageList(1, 10, out allRowsCount, new { ID = 1 }, sort);
3、DapperExtensions+lambda
//SELECT [Users].[UserId], // [Users].[LoginName], // [Users].[Password] //FROM [Users] //WHERE [Users].[LoginName] = @LoginName_1 var fromDemo = this.LambdaQuery().Select(p => new { p.UserId, p.LoginName, p.Password }) //不支持As .Where(p => p.LoginName == "很好很強大"); //支持 返回 DataReader、DataSet、DataTable、 泛型集合 fromDemo.ToDataReader(); fromDemo.ToDataSet(); fromDemo.ToDataTable(); IEnumerable<UsersModel> list = fromDemo.ToList<UsersModel>(); var select = new Select<UsersEntity>(); select.AddSelect(p => p.Remark.As("Remark")); //Expression<Func<T, bool>>類型支持 as 語法 fromDemo = this.LambdaQuery().AddSelect(select); // SELECT [Users].[UserId], // [Users].[LoginName], // [Users].[Password], // [Users].[Status], // [Users].[CreateTime], // [Users].[UpdateTime], // [Users].[Remark] //FROM [Users] //WHERE ( // ( // ([Users].[LoginName] LIKE @LoginName_1) // AND ([Users].[Status] NOT IN (@Status_2, @Status_3, @Status_4)) // ) // AND ([Users].[CreateTime] >= @CreateTime_5) // ) // AND ([Users].[UpdateTime] IS NOT NULL) var fromDemo2 = this.LambdaQuery().Where(p => p.LoginName.Like("%王老五%") //like && p.Status.NotIn<string>("1", "2", "3") //in or not in && p.CreateTime >= Convert.ToDateTime("2016-01-21") //時間比較 && p.UpdateTime.IsNotNull() //is null ); //SELECT [Users].[UserId], // [Users].[LoginName], // [Users].[Password], // [Users].[Status], // [Users].[CreateTime], // [Users].[UpdateTime], // [Users].[Remark] //FROM [Users] //WHERE ( // ( // ([Users].[LoginName] LIKE @LoginName_1) // AND ([Users].[Status] = @Status_2) // ) // OR ([Users].[UserId] = @UserId_3) // ) var where = new Where<UsersEntity>(); where.And(p => p.LoginName.Like("%李二蛋%") && p.Status == 1); where.Or(p => p.UserId == 1); var fromDemo3 = this.LambdaQuery().Where(where); //SELECT [Users].[UserId], // [Users].[LoginName], // [Users].[Password], // [Users].[Status], // [Users].[CreateTime], // [Users].[UpdateTime], // [Users].[Remark] //FROM [Users] //ORDER BY // CreateTime ASC, // UpdateTime ASC, // UserId DESC var fromDemo4 = this.LambdaQuery().OrderBy(p => new { p.CreateTime, p.UpdateTime }).AddOrderByDescending(p => new { p.UserId }); //"SELECT * FROM [Users] INNER JOIN UserInfo ON ([Users].[UserId] = [UserInfo].[UserId]) " var fromDemo5 = this.LambdaQuery().InnerJoin<UserInfoEntity>((u, ui) => u.UserId == ui.UserId); //SELECT DISTINCT TOP 100 * //FROM [Users] WITH (NOLOCK) INNER // JOIN UserInfo WITH (NOLOCK) // ON ([Users].[UserId] = [UserInfo].[UserId]) var fromDemo6 = this.LambdaQuery() .InnerJoin<UserInfoEntity>((u, ui) => u.UserId == ui.UserId).WithNoLock().Top(100).Distinct(); //SELECT TOP(10) [_proj].* //FROM ( // SELECT ROW_NUMBER() OVER(ORDER BY CURRENT_TIMESTAMP) AS [_row_number], // * // FROM [Users] WITH (NOLOCK) LEFT // JOIN UserInfo WITH (NOLOCK) // ON ([Users].[UserId] = [UserInfo].[UserId]) // WHERE ([Users].[UserId] > @UserId_1) // AND ([UserInfo].[Sex] = @Sex_2) // ) [_proj] //WHERE [_proj].[_row_number] >= @_pageStartRow //ORDER BY // [_proj].[_row_number] var fromDemo7 = this.LambdaQuery() .LeftJoin<UserInfoEntity>((u, ui) => u.UserId == ui.UserId).WithNoLock() .Where<UserInfoEntity>((u, ui) => u.UserId > 1 && ui.Sex == 1) .Page(2, 10); //DELETE //FROM [Users] //WHERE ([Users].[Status] = @Status_1) // AND ( //[Users].[CreateTime] > @CreateTime_2 var deleteDemo = this.LambdaDelete() .Where(p => p.Status == 1 && p.CreateTime > DateTime.Now); //UPDATE [Users] //SET [Users].[Remark] = @Remark_3 //WHERE [Users].[Status] = @Status_4 var updateDemo = this.LambdaUpdate() .Set(p => p.Remark == "Remark") .Where(p => p.Status == 1);
對於lambda 支持 select + As 、where 、各種左右連接、 orderby 、grouy by、 HAVING、 WITH(NOLOCK) (支持sqlserver)、 Top、Distinct、
(支持sql垮數據庫查詢,加入DbName、SchemaName配置)
簡單的語法都支持了,但是還有些特殊的sql 語法 介於Lambda的語法問題暫時沒辦法支持。不過Dos.ORM做到了一些特殊的支持。
之前也和Dos.ORM的作者交流過。 目前都不支持 select * from User a INNER join User b on a.id=b.pid 這類 別名且自join查詢,實現起來很麻煩。
這里我就放棄了,有些功能在考慮到性能和設計方面得不償失。
比如一個特別復雜的sql ,非要用ORM來實現,那其實已經超出ORM的能力范圍了。且不論性能問題和代碼支持問題, 單單代碼可讀性就降低很多啊
相信直接看sql 比直接看 orm語法 看的爽吧 。
性能:
用lambda生成sql用時也就2,3 毫秒的樣子, 所以在執行和映射能力方面我就不擔心了。最后還是寫了個小測試:
之前有很多小伙伴不太了解如何使用或者調用, 這里簡單的寫個Demo, (下載地址在下面 )
1.針對Repository的類圖如下:
2、Demo的 架構如下:
歡迎老大們拍磚指點。
覺得有用請點下推薦吧,你的推薦是我發帖的動力。
https://git.oschina.net/hy59005271/DapperExtensions_Demo
有新的擴展和bug會及時更新
相關文章:
搭建一套自己實用的.net架構(3)【ORM-Dapper+DapperExtensions】
原文鏈接:http://www.cnblogs.com/hy59005271/p/5604118.html