搭建一套自己实用的.net架构(3)续 【ORM Dapper+DapperExtensions+Lambda】

      前言

      继之前发的帖子【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

 

posted @ 2016-06-21 16:36  咖啡不苦不舒服  阅读(13260)  评论(65编辑  收藏  举报